diff --git a/build/data/libobs/default.effect b/build/data/libobs/default.effect index 1e97f480d..e5ad2b3fb 100644 --- a/build/data/libobs/default.effect +++ b/build/data/libobs/default.effect @@ -1,6 +1,6 @@ uniform float4x4 ViewProj; uniform float4x4 color_matrix; -uniform texture2d diffuse; +uniform texture2d image; sampler_state def_sampler { Filter = Linear; @@ -23,12 +23,12 @@ VertInOut VSDefault(VertInOut vert_in) float4 PSDrawBare(VertInOut vert_in) : TARGET { - return diffuse.Sample(def_sampler, vert_in.uv); + return image.Sample(def_sampler, vert_in.uv); } float4 PSDrawMatrix(VertInOut vert_in) : TARGET { - float4 yuv = diffuse.Sample(def_sampler, vert_in.uv); + float4 yuv = image.Sample(def_sampler, vert_in.uv); return saturate(mul(float4(yuv.xyz, 1.0), color_matrix)); } diff --git a/libobs/graphics/effect.c b/libobs/graphics/effect.c index 7c50711c8..dd56ca340 100644 --- a/libobs/graphics/effect.c +++ b/libobs/graphics/effect.c @@ -253,8 +253,24 @@ eparam_t effect_getworldmatrix(effect_t effect) static inline void effect_setval_inline(effect_t effect, eparam_t param, const void *data, size_t size) { - bool size_changed = param->cur_val.num != size; + bool size_changed; + if (!effect) { + blog(LOG_WARNING, "effect_setval_inline: invalid effect"); + return; + } + + if (!param) { + blog(LOG_WARNING, "effect_setval_inline: invalid param"); + return; + } + + if (!data) { + blog(LOG_WARNING, "effect_setval_inline: invalid data"); + return; + } + + size_changed = param->cur_val.num != size; if (!matching_effect(effect, param)) return; diff --git a/libobs/media-io/format-conversion.c b/libobs/media-io/format-conversion.c index dbf92bff1..59d70e456 100644 --- a/libobs/media-io/format-conversion.c +++ b/libobs/media-io/format-conversion.c @@ -19,15 +19,8 @@ #include #include -static FORCE_INLINE uint32_t get_m128_32_0(const __m128i val) -{ - return *(uint32_t* const)&val; -} - -static FORCE_INLINE uint32_t get_m128_32_1(const __m128i val) -{ - return *(((uint32_t* const)&val)+1); -} +#define get_m128_32_0(val) (*((uint32_t*)&val)) +#define get_m128_32_1(val) (*(((uint32_t*)&val)+1)) static FORCE_INLINE void pack_lum(uint8_t *lum_plane, uint32_t lum_pos0, uint32_t lum_pos1, diff --git a/libobs/obs-defs.h b/libobs/obs-defs.h index c15b36c0b..542660376 100644 --- a/libobs/obs-defs.h +++ b/libobs/obs-defs.h @@ -17,17 +17,11 @@ #pragma once -/* Maximum number of source channels for output and per display */ +/** Maximum number of source channels for output and per display */ #define MAX_CHANNELS 32 -#define MODULE_SUCCESS 0 -#define MODULE_ERROR -1 -#define MODULE_FILENOTFOUND -2 -#define MODULE_FUNCTIONNOTFOUND -3 -#define MODULE_INCOMPATIBLE_VER -4 - -#define SOURCE_VIDEO (1<<0) /* Source has video */ -#define SOURCE_AUDIO (1<<1) /* Source has audio */ -#define SOURCE_ASYNC_VIDEO (1<<2) /* Async video (use with SOURCE_VIDEO) */ -#define SOURCE_DEFAULT_EFFECT (1<<3) /* Source uses default/filter effect */ -#define SOURCE_YUV (1<<4) /* Source is in YUV color space */ +#define MODULE_SUCCESS 0 +#define MODULE_ERROR -1 +#define MODULE_FILE_NOT_FOUND -2 +#define MODULE_FUNCTION_NOT_FOUND -3 +#define MODULE_INCOMPATIBLE_VER -4 diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index 79f5b5a99..9194fd0d8 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -18,29 +18,10 @@ #include "obs.h" #include "obs-internal.h" -bool load_encoder_info(void *module, const char *module_name, - const char *id, struct encoder_info *info) -{ - LOAD_MODULE_SUBFUNC(getname, true); - LOAD_MODULE_SUBFUNC(create, true); - LOAD_MODULE_SUBFUNC(destroy, true); - LOAD_MODULE_SUBFUNC(update, true); - LOAD_MODULE_SUBFUNC(reset, true); - LOAD_MODULE_SUBFUNC(encode, true); - LOAD_MODULE_SUBFUNC(getheader, true); - - LOAD_MODULE_SUBFUNC(properties, false); - LOAD_MODULE_SUBFUNC(setbitrate, false); - LOAD_MODULE_SUBFUNC(request_keyframe, false); - - info->id = id; - return true; -} - -static inline struct encoder_info *get_encoder_info(const char *id) +static inline struct obs_encoder_info *get_encoder_info(const char *id) { for (size_t i = 0; i < obs->encoder_types.num; i++) { - struct encoder_info *info = obs->encoder_types.array+i; + struct obs_encoder_info *info = obs->encoder_types.array+i; if (strcmp(info->id, id) == 0) return info; @@ -51,7 +32,7 @@ static inline struct encoder_info *get_encoder_info(const char *id) const char *obs_encoder_getdisplayname(const char *id, const char *locale) { - struct encoder_info *ei = get_encoder_info(id); + struct obs_encoder_info *ei = get_encoder_info(id); if (!ei) return NULL; @@ -62,13 +43,13 @@ obs_encoder_t obs_encoder_create(const char *id, const char *name, obs_data_t settings) { struct obs_encoder *encoder; - struct encoder_info *ei = get_encoder_info(id); + struct obs_encoder_info *ei = get_encoder_info(id); if (!ei) return NULL; encoder = bzalloc(sizeof(struct obs_encoder)); - encoder->callbacks = *ei; + encoder->info = *ei; if (pthread_mutex_init(&encoder->data_callbacks_mutex, NULL) != 0) { bfree(encoder); @@ -98,7 +79,7 @@ void obs_encoder_destroy(obs_encoder_t encoder) da_erase_item(obs->data.encoders, &encoder); pthread_mutex_unlock(&obs->data.encoders_mutex); - encoder->callbacks.destroy(encoder->data); + encoder->info.destroy(encoder->data); obs_data_release(encoder->settings); bfree(encoder); } @@ -106,7 +87,7 @@ void obs_encoder_destroy(obs_encoder_t encoder) obs_properties_t obs_encoder_properties(const char *id, const char *locale) { - const struct encoder_info *ei = get_encoder_info(id); + const struct obs_encoder_info *ei = get_encoder_info(id); if (ei && ei->properties) return ei->properties(locale); return NULL; @@ -115,40 +96,40 @@ obs_properties_t obs_encoder_properties(const char *id, const char *locale) void obs_encoder_update(obs_encoder_t encoder, obs_data_t settings) { obs_data_replace(&encoder->settings, settings); - encoder->callbacks.update(encoder->data, encoder->settings); + encoder->info.update(encoder->data, encoder->settings); } bool obs_encoder_reset(obs_encoder_t encoder) { - return encoder->callbacks.reset(encoder->data); + return encoder->info.reset(encoder->data); } bool obs_encoder_encode(obs_encoder_t encoder, void *frames, size_t size) { /* TODO */ - //encoder->callbacks.encode(encoder->data, frames, size, packets); + //encoder->info.encode(encoder->data, frames, size, packets); return false; } int obs_encoder_getheader(obs_encoder_t encoder, struct encoder_packet **packets) { - return encoder->callbacks.getheader(encoder, packets); + return encoder->info.getheader(encoder, packets); } bool obs_encoder_setbitrate(obs_encoder_t encoder, uint32_t bitrate, uint32_t buffersize) { - if (encoder->callbacks.setbitrate) - return encoder->callbacks.setbitrate(encoder->data, bitrate, + if (encoder->info.setbitrate) + return encoder->info.setbitrate(encoder->data, bitrate, buffersize); return false; } bool obs_encoder_request_keyframe(obs_encoder_t encoder) { - if (encoder->callbacks.request_keyframe) - return encoder->callbacks.request_keyframe(encoder->data); + if (encoder->info.request_keyframe) + return encoder->info.request_keyframe(encoder->data); return false; } diff --git a/libobs/obs-encoder.h b/libobs/obs-encoder.h index 49feb7a0f..4260bc9f2 100644 --- a/libobs/obs-encoder.h +++ b/libobs/obs-encoder.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2013-2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,125 +17,14 @@ #pragma once -#include "util/c99defs.h" -#include "util/dstr.h" - -/* - * =========================================== - * Encoders - * =========================================== - * - * An encoder context allows data to be encoded from raw output, and allow - * it to be used to output contexts (such as outputting to stream). - * - * A module with encoders needs to export these functions: - * + enum_encoders - * - * Each individual encoder is then exported by it's name. For example, an - * encoder named "myencoder" would have the following exports: - * + myencoder_getname - * + myencoder_create - * + myencoder_destroy - * + myencoder_update - * + myencoder_reset - * + myencoder_encode - * + myencoder_getheader - * - * [and optionally] - * + myencoder_properties - * + myencoder_setbitrate - * + myencoder_request_keyframe - * - * =========================================== - * Primary Exports - * =========================================== - * const char *enum_encoders(size_t idx); - * idx: index of the encoder. - * Return value: Encoder identifier name. NULL when no more available. - * - * =========================================== - * Encoder Exports - * =========================================== - * const char *[name]_getname(const char *locale); - * Returns the full translated name of the encoder type - * (seen by the user). - * - * --------------------------------------------------------- - * void *[name]_create(obs_data_t settings, const char *name, - * obs_encoder_t encoder); - * Creates an encoder. - * - * settings: Settings of the encoder. - * name: Name of the encoder. - * encoder: Pointer to encoder context. - * Return value: Internal encoder pointer, or NULL if failed. - * - * --------------------------------------------------------- - * void [name]_destroy(void *data); - * Destroys the encoder. - * - * --------------------------------------------------------- - * void [name]_update(void *data, obs_data_t settings) - * Updates the encoder's settings - * - * settings: New settings of the encoder - * - * --------------------------------------------------------- - * bool [name]_reset(void *data) - * Restarts encoder - * - * Return value: true if successful - * - * --------------------------------------------------------- - * int [name]_encode(void *data, void *frames, size_t size, - * struct encoder_packet **packets) - * Encodes data. - * - * frames: frame data - * size: size of data pointed to by the frame parameter - * packets: returned packets, or NULL if none - * Return value: number of encoder frames - * - * --------------------------------------------------------- - * int [name]_getheader(void *data, struct encoder_packet **packets) - * Returns the header packets for this encoder. - * - * packets: returned packets, or NULL if none - * Return value: number of encoder frames - * - * =========================================== - * Optional Encoder Exports - * =========================================== - * obs_properties_t [name]_properties(const char *locale); - * Returns the properties of this particular encoder type, if any. - * - * --------------------------------------------------------- - * bool [name]_setbitrate(void *data, uint32_t bitrate, uint32_t buffersize); - * Sets the bitrate of the encoder - * - * bitrate: Bitrate - * buffersize: Buffer size - * Returns true if successful/compatible - * - * --------------------------------------------------------- - * bool [name]_request_keyframe(void *data) - * Requests a keyframe from the encoder - * - * Returns true if successful/compatible. - */ - -struct obs_encoder; - -struct encoder_info { +struct obs_encoder_info { const char *id; const char *(*getname)(const char *locale); - void *(*create)(obs_data_t settings, struct obs_encoder *encoder); + void *(*create)(obs_data_t settings, obs_encoder_t encoder); void (*destroy)(void *data); - void (*update)(void *data, obs_data_t settings); - bool (*reset)(void *data); int (*encode)(void *data, void *frames, size_t size, @@ -143,26 +32,12 @@ struct encoder_info { int (*getheader)(void *data, struct encoder_packet **packets); /* optional */ + void (*update)(void *data, obs_data_t settings); + obs_properties_t (*properties)(const char *locale); bool (*setbitrate)(void *data, uint32_t bitrate, uint32_t buffersize); bool (*request_keyframe)(void *data); }; -struct obs_encoder_callback { - void (*new_packet)(void *param, struct encoder_packet *packet); - void *param; -}; - -struct obs_encoder { - char *name; - void *data; - struct encoder_info callbacks; - obs_data_t settings; - - pthread_mutex_t data_callbacks_mutex; - DARRAY(struct obs_encoder_callback) data_callbacks; -}; - -extern bool load_encoder_info(void *module, const char *module_name, - const char *encoder_name, struct encoder_info *info); +EXPORT void obs_register_encoder(const struct obs_encoder_info *info); diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index cd829b5bc..d704bb789 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2013-2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,39 +17,37 @@ #pragma once +#include "util/c99defs.h" #include "util/darray.h" +#include "util/dstr.h" #include "util/threading.h" +#include "callback/signal.h" +#include "callback/proc.h" #include "graphics/graphics.h" +#include "media-io/audio-resampler.h" #include "media-io/video-io.h" #include "media-io/audio-io.h" #include "obs.h" -#include "obs-module.h" -#include "obs-source.h" -#include "obs-output.h" -#include "obs-service.h" -#include "obs-encoder.h" - -#define LOAD_MODULE_SUBFUNC(name, required) \ - do { \ - info->name = load_module_subfunc(module, module_name, \ - id, #name, required); \ - if (required && !info->name) \ - return false; \ - } while (false) #define NUM_TEXTURES 2 -struct obs_display { - swapchain_t swap; /* can be NULL if just sound */ - obs_source_t channels[MAX_CHANNELS]; - - /* TODO: sound output target */ -}; /* ------------------------------------------------------------------------- */ +/* core */ + +struct obs_module { + char *name; + void *module; +}; + +extern void free_module(struct obs_module *mod); + + +/* ------------------------------------------------------------------------- */ +/* core */ struct obs_core_video { graphics_t graphics; @@ -96,26 +94,129 @@ struct obs_core_data { }; struct obs_core { - DARRAY(struct obs_module) modules; - DARRAY(struct source_info) input_types; - DARRAY(struct source_info) filter_types; - DARRAY(struct source_info) transition_types; - DARRAY(struct output_info) output_types; - DARRAY(struct encoder_info) encoder_types; - DARRAY(struct service_info) service_types; - DARRAY(struct obs_modal_ui) ui_modal_callbacks; - DARRAY(struct obs_modeless_ui) ui_modeless_callbacks; + DARRAY(struct obs_module) modules; + DARRAY(struct obs_source_info) input_types; + DARRAY(struct obs_source_info) filter_types; + DARRAY(struct obs_source_info) transition_types; + DARRAY(struct obs_output_info) output_types; + DARRAY(struct obs_encoder_info) encoder_types; + DARRAY(struct obs_service_info) service_types; + DARRAY(struct obs_modal_ui) modal_ui_callbacks; + DARRAY(struct obs_modeless_ui) modeless_ui_callbacks; - signal_handler_t signals; - proc_handler_t procs; + signal_handler_t signals; + proc_handler_t procs; /* segmented into multiple sub-structures to keep things a bit more * clean and organized */ - struct obs_core_video video; - struct obs_core_audio audio; - struct obs_core_data data; + struct obs_core_video video; + struct obs_core_audio audio; + struct obs_core_data data; }; extern struct obs_core *obs; extern void *obs_video_thread(void *param); + + +/* ------------------------------------------------------------------------- */ +/* displays */ + +struct obs_display { + swapchain_t swap; /* can be NULL if just sound */ + obs_source_t channels[MAX_CHANNELS]; + + /* TODO: sound output target */ +}; + + +/* ------------------------------------------------------------------------- */ +/* sources */ + +struct obs_source { + volatile int refs; + struct obs_source_info info; + + /* source-specific data */ + char *name; /* user-defined name */ + enum obs_source_type type; + obs_data_t settings; + void *data; + + signal_handler_t signals; + proc_handler_t procs; + + /* used to indicate that the source has been removed and all + * references to it should be released (not exactly how I would prefer + * to handle things but it's the best option) */ + bool removed; + + /* timing (if video is present, is based upon video) */ + volatile bool timing_set; + volatile uint64_t timing_adjust; + volatile int audio_reset_ref; + uint64_t next_audio_ts_min; + uint64_t last_frame_ts; + uint64_t last_sys_timestamp; + + /* audio */ + bool audio_failed; + struct resample_info sample_info; + audio_resampler_t resampler; + audio_line_t audio_line; + pthread_mutex_t audio_mutex; + struct filtered_audio audio_data; + size_t audio_storage_size; + float volume; + + /* async video data */ + texture_t output_texture; + DARRAY(struct source_frame*) video_frames; + pthread_mutex_t video_mutex; + + /* filters */ + struct obs_source *filter_parent; + struct obs_source *filter_target; + DARRAY(struct obs_source*) filters; + pthread_mutex_t filter_mutex; + texrender_t filter_texrender; + bool rendering_filter; +}; + +bool obs_source_init_handlers(struct obs_source *source); +extern bool obs_source_init(struct obs_source *source, + const struct obs_source_info *info); + +extern void obs_source_activate(obs_source_t source); +extern void obs_source_deactivate(obs_source_t source); +extern void obs_source_video_tick(obs_source_t source, float seconds); + + +/* ------------------------------------------------------------------------- */ +/* outputs */ + +struct obs_output { + char *name; + void *data; + struct obs_output_info info; + obs_data_t settings; +}; + + +/* ------------------------------------------------------------------------- */ +/* encoders */ + +struct obs_encoder_callback { + void (*new_packet)(void *param, struct encoder_packet *packet); + void *param; +}; + +struct obs_encoder { + char *name; + void *data; + struct obs_encoder_info info; + obs_data_t settings; + + pthread_mutex_t data_callbacks_mutex; + DARRAY(struct obs_encoder_callback) data_callbacks; +}; diff --git a/libobs/obs-module.c b/libobs/obs-module.c index 8ed35de8b..bf58d727b 100644 --- a/libobs/obs-module.c +++ b/libobs/obs-module.c @@ -22,133 +22,71 @@ #include "obs-internal.h" #include "obs-module.h" -void *load_module_subfunc(void *module, const char *module_name, - const char *name, const char *func, bool required) -{ - struct dstr func_name; - void *func_addr = NULL; - - dstr_init_copy(&func_name, name); - dstr_cat(&func_name, "_"); - dstr_cat(&func_name, func); - - func_addr = os_dlsym(module, func_name.array); - if (required && !func_addr) - blog(LOG_ERROR, "Could not load function '%s' from module '%s'", - func_name.array, module_name); - - dstr_free(&func_name); - return func_addr; -} - -static void module_load_exports(struct obs_module *mod, - struct darray *output_array, const char *type, - const size_t data_size, void *callback_ptr) -{ - bool (*enum_func)(size_t idx, const char **name); - bool (*callback)(void*, const char*, const char*, void*); - struct dstr enum_name; - const char *name; - size_t i = 0; - - callback = callback_ptr; - - dstr_init_copy(&enum_name, "enum_"); - dstr_cat(&enum_name, type); - - enum_func = os_dlsym(mod->module, enum_name.array); - if (!enum_func) - goto complete; - - while (enum_func(i++, &name)) { - void *info = bmalloc(data_size); - if (!callback(mod->module, mod->name, name, info)) - blog(LOG_ERROR, "Couldn't load '%s' because it " - "was missing required functions", - name); - else - darray_push_back(data_size, output_array, info); - - bfree(info); - } - -complete: - dstr_free(&enum_name); -} - -static void module_load_modal_ui_exports(struct obs_module *mod) -{ - bool (*enum_func)(size_t idx, struct obs_modal_ui *info); - struct obs_modal_ui ui_info; - size_t i = 0; - - enum_func = os_dlsym(mod->module, "enum_modal_ui"); - if (enum_func) - while (enum_func(i++, &ui_info)) - da_push_back(obs->ui_modal_callbacks, &ui_info); -} - -static void module_load_modeless_ui_exports(struct obs_module *mod) -{ - bool (*enum_func)(size_t idx, struct obs_modeless_ui *info); - struct obs_modeless_ui ui_info; - size_t i = 0; - - enum_func = os_dlsym(mod->module, "enum_modeless_ui"); - if (enum_func) - while (enum_func(i++, &ui_info)) - da_push_back(obs->ui_modeless_callbacks, &ui_info); -} - extern char *find_plugin(const char *plugin); -/* checks API version of module and calls module_load if it exists. - * if the API version used by the module is incompatible, fails. */ +/* These variables get the current size of the info structures. Used to + * automatically prevent API breakage in case functions have to be added */ +static size_t cur_source_info_size = 0; +static size_t cur_output_info_size = 0; +static size_t cur_encoder_info_size = 0; +static size_t cur_service_info_size = 0; +static size_t cur_modal_ui_size = 0; +static size_t cur_modeless_ui_size = 0; + +static inline int req_func_not_found(const char *name, const char *path) +{ + blog(LOG_WARNING, "Required module function '%s' in module '%s' not " + "found, loading of module failed", + name, path); + return MODULE_FUNCTION_NOT_FOUND; +} + +#define LOAD_REQ_SIZE_FUNC(func, module, path) \ + func = os_dlsym(module, #func); \ + if (!func) \ + return req_func_not_found(#func, path) + static int call_module_load(void *module, const char *path) { - uint32_t (*module_version)(uint32_t obs_ver) = NULL; - bool (*module_load)(void) = NULL; - uint32_t version, major, minor; + bool (*obs_module_load)(uint32_t obs_ver) = NULL; + size_t (*obs_module_source_info_size)(void) = NULL; + size_t (*obs_module_output_info_size)(void) = NULL; + size_t (*obs_module_encoder_info_size)(void) = NULL; + size_t (*obs_module_service_info_size)(void) = NULL; + size_t (*obs_module_modal_ui_size)(void) = NULL; + size_t (*obs_module_modeless_ui_size)(void) = NULL; - module_load = os_dlsym(module, "module_load"); + obs_module_load = os_dlsym(module, "obs_module_load"); + if (!obs_module_load) + return req_func_not_found("obs_module_load", path); - module_version = os_dlsym(module, "module_version"); - if (!module_version) { + LOAD_REQ_SIZE_FUNC(obs_module_source_info_size, module, path); + LOAD_REQ_SIZE_FUNC(obs_module_output_info_size, module, path); + LOAD_REQ_SIZE_FUNC(obs_module_encoder_info_size, module, path); + LOAD_REQ_SIZE_FUNC(obs_module_service_info_size, module, path); + LOAD_REQ_SIZE_FUNC(obs_module_modal_ui_size, module, path); + LOAD_REQ_SIZE_FUNC(obs_module_modeless_ui_size, module, path); + + cur_source_info_size = obs_module_source_info_size(); + cur_output_info_size = obs_module_output_info_size(); + cur_encoder_info_size = obs_module_encoder_info_size(); + cur_service_info_size = obs_module_service_info_size(); + cur_modal_ui_size = obs_module_modal_ui_size(); + cur_modeless_ui_size = obs_module_modeless_ui_size(); + + if (!obs_module_load(LIBOBS_API_VER)) { blog(LOG_WARNING, "Module '%s' failed to load: " - "module_version not found.", path); - return MODULE_FUNCTIONNOTFOUND; - } - - version = module_version(LIBOBS_API_VER); - major = (version >> 16); - minor = (version & 0xFF); - - if (major != LIBOBS_API_MAJOR_VER) { - blog(LOG_WARNING, "Module '%s' failed to load: " - "incompatible major version " - "(current API: %u.%u, module version: %u.%u)", - path, - LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, - major, minor); - return MODULE_INCOMPATIBLE_VER; - } - - if (minor > LIBOBS_API_MINOR_VER) { - blog(LOG_WARNING, "Module '%s' failed to load: " - "incompatible minor version " - "(current API: %u.%u, module version: %u.%u)", - path, - LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, - major, minor); - return MODULE_INCOMPATIBLE_VER; - } - - if (module_load && !module_load()) { - blog(LOG_WARNING, "Module '%s' failed to load: " - "module_load failed", path); + "obs_module_load failed", path); return MODULE_ERROR; } + cur_source_info_size = 0; + cur_output_info_size = 0; + cur_encoder_info_size = 0; + cur_service_info_size = 0; + cur_modal_ui_size = 0; + cur_modeless_ui_size = 0; + return MODULE_SUCCESS; } @@ -161,7 +99,7 @@ int obs_load_module(const char *path) mod.module = os_dlopen(plugin_path); bfree(plugin_path); if (!mod.module) - return MODULE_FILENOTFOUND; + return MODULE_FILE_NOT_FOUND; errorcode = call_module_load(mod.module, path); if (errorcode != MODULE_SUCCESS) { @@ -170,20 +108,6 @@ int obs_load_module(const char *path) } mod.name = bstrdup(path); - module_load_exports(&mod, &obs->input_types.da, "inputs", - sizeof(struct source_info), load_source_info); - module_load_exports(&mod, &obs->filter_types.da, "filters", - sizeof(struct source_info), load_source_info); - module_load_exports(&mod, &obs->transition_types.da, "transitions", - sizeof(struct source_info), load_source_info); - module_load_exports(&mod, &obs->output_types.da, "outputs", - sizeof(struct output_info), load_output_info); - module_load_exports(&mod, &obs->encoder_types.da, "encoders", - sizeof(struct encoder_info), load_encoder_info); - - module_load_modal_ui_exports(&mod); - module_load_modeless_ui_exports(&mod); - da_push_back(obs->modules, &mod); return MODULE_SUCCESS; } @@ -196,8 +120,7 @@ void free_module(struct obs_module *mod) if (mod->module) { void (*module_unload)(void); - module_unload = os_dlsym(mod->module, - "module_unload"); + module_unload = os_dlsym(mod->module, "module_unload"); if (module_unload) module_unload(); @@ -206,3 +129,111 @@ void free_module(struct obs_module *mod) bfree(mod->name); } + +void obs_register_source(const struct obs_source_info *info) +{ + struct obs_source_info data = {0}; + struct darray *array; + + if (!cur_source_info_size) { + blog(LOG_WARNING, "Tried to register obs_source_info" + " outside of obs_module_load"); + return; + } + + memcpy(&data, info, cur_source_info_size); + + if (info->type == OBS_SOURCE_TYPE_INPUT) { + array = &obs->input_types.da; + } else if (info->type == OBS_SOURCE_TYPE_FILTER) { + array = &obs->filter_types.da; + } else if (info->type == OBS_SOURCE_TYPE_TRANSITION) { + array = &obs->transition_types.da; + } else { + blog(LOG_WARNING, "Tried to register unknown source type: %u", + info->type); + return; + } + + darray_push_back(sizeof(struct obs_source_info), array, &data); +} + +#define REGISTER_OBS_DEF(size_var, structure, dest, info) \ + do { \ + struct structure data = {0}; \ + if (!size_var) { \ + blog(LOG_WARNING, "Tried to register " #structure \ + " outside of obs_module_load"); \ + return; \ + } \ + \ + memcpy(&data, info, size_var); \ + da_push_back(dest, &data); \ + } while (false) + +#define CHECK_REQUIRED_VAL(info, val, func) \ + do { \ + if (!info->val) {\ + blog(LOG_WARNING, "Required value '" #val " for" \ + "'%s' not found. " #func \ + " failed.", \ + info->id);\ + return; \ + } \ + } while (false) + +void obs_register_output(const struct obs_output_info *info) +{ + CHECK_REQUIRED_VAL(info, getname, obs_register_output); + CHECK_REQUIRED_VAL(info, create, obs_register_output); + CHECK_REQUIRED_VAL(info, destroy, obs_register_output); + CHECK_REQUIRED_VAL(info, start, obs_register_output); + CHECK_REQUIRED_VAL(info, stop, obs_register_output); + CHECK_REQUIRED_VAL(info, active, obs_register_output); + + REGISTER_OBS_DEF(cur_output_info_size, obs_output_info, + obs->output_types, info); +} + +void obs_register_encoder(const struct obs_encoder_info *info) +{ + CHECK_REQUIRED_VAL(info, getname, obs_register_encoder); + CHECK_REQUIRED_VAL(info, create, obs_register_encoder); + CHECK_REQUIRED_VAL(info, destroy, obs_register_encoder); + CHECK_REQUIRED_VAL(info, reset, obs_register_encoder); + CHECK_REQUIRED_VAL(info, encode, obs_register_encoder); + CHECK_REQUIRED_VAL(info, getheader, obs_register_encoder); + + REGISTER_OBS_DEF(cur_encoder_info_size, obs_encoder_info, + obs->encoder_types, info); +} + +void obs_register_service(const struct obs_service_info *info) +{ + CHECK_REQUIRED_VAL(info, getname, obs_register_service); + CHECK_REQUIRED_VAL(info, create, obs_register_service); + CHECK_REQUIRED_VAL(info, destroy, obs_register_service); + + REGISTER_OBS_DEF(cur_service_info_size, obs_service_info, + obs->service_types, info); +} + +void obs_regsiter_modal_ui(const struct obs_modal_ui *info) +{ + CHECK_REQUIRED_VAL(info, task, obs_regsiter_modal_ui); + CHECK_REQUIRED_VAL(info, target, obs_regsiter_modal_ui); + CHECK_REQUIRED_VAL(info, exec, obs_regsiter_modal_ui); + + REGISTER_OBS_DEF(cur_modal_ui_size, obs_modal_ui, + obs->modal_ui_callbacks, info); +} + +void obs_regsiter_modeless_ui(const struct obs_modeless_ui *info) +{ + CHECK_REQUIRED_VAL(info, task, obs_regsiter_modeless_ui); + CHECK_REQUIRED_VAL(info, target, obs_regsiter_modeless_ui); + CHECK_REQUIRED_VAL(info, create, obs_regsiter_modeless_ui); + + REGISTER_OBS_DEF(cur_modeless_ui_size, obs_modeless_ui, + obs->modeless_ui_callbacks, info); +} diff --git a/libobs/obs-module.h b/libobs/obs-module.h index da582966e..03ffb6e5c 100644 --- a/libobs/obs-module.h +++ b/libobs/obs-module.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,13 +17,61 @@ #pragma once -#include "util/darray.h" +#include "obs.h" -struct obs_module { - char *name; - void *module; -}; +#ifdef __cplusplus +#define MODULE_EXPORT extern "C" EXPORT +#else +#define MODULE_EXPORT EXPORT +#endif -extern void *load_module_subfunc(void *module, const char *module_name, - const char *name, const char *func, bool required); -extern void free_module(struct obs_module *mod); +#define OBS_SIZE_FUNC(structure, func) \ + MODULE_EXPORT size_t func(void); \ + size_t func(void) {return sizeof(struct structure);} + +/** + * @file + * + * This file is used by modules for module declaration and module exports. + */ + +/** Required: Declares a libobs module. */ +#define OBS_DECLARE_MODULE() \ + MODULE_EXPORT uint32_t obs_module_ver(void); \ + uint32_t obs_module_ver(void) {return LIBOBS_API_VER;} \ + OBS_SIZE_FUNC(obs_source_info, obs_module_source_info_size) \ + OBS_SIZE_FUNC(obs_output_info, obs_module_output_info_size) \ + OBS_SIZE_FUNC(obs_encoder_info, obs_module_encoder_info_size) \ + OBS_SIZE_FUNC(obs_encoder_info, obs_module_service_info_size) \ + OBS_SIZE_FUNC(obs_modal_ui, obs_module_modal_ui_size) \ + OBS_SIZE_FUNC(obs_modeless_ui, obs_module_modeless_ui_size) + +/** + * Required: Called when the module is loaded. Use this function to load all + * the sources/encoders/outputs/services for your module, or anything else that + * may need loading. + * + * @param libobs_ver The version of libobs. + * @return Return true to continue loading the module, otherwise + * false to indcate failure and unload the module + */ +MODULE_EXPORT bool obs_module_load(uint32_t libobs_version); + +/** Optional: Called when the module is unloaded. */ +MODULE_EXPORT void obs_module_unload(void); + +/** + * Optional: Declares the author(s) of the module + * + * @param name Author name(s) + */ +#define OBS_MODULE_AUTHOR(name) \ + MODULE_EXPORT const char *obs_module_author(void); \ + const char *obs_module_author(void) {return name;} + +/** + * Optional: Declares the author of the module + * + * @param locale Locale to look up the description for. + */ +MODULE_EXPORT const char *obs_module_description(const char *locale); diff --git a/libobs/obs-output.c b/libobs/obs-output.c index f798109be..1582802e5 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -18,25 +18,7 @@ #include "obs.h" #include "obs-internal.h" -bool load_output_info(void *module, const char *module_name, - const char *id, struct output_info *info) -{ - LOAD_MODULE_SUBFUNC(getname, true); - LOAD_MODULE_SUBFUNC(create, true); - LOAD_MODULE_SUBFUNC(destroy, true); - LOAD_MODULE_SUBFUNC(update, true); - LOAD_MODULE_SUBFUNC(start, true); - LOAD_MODULE_SUBFUNC(stop, true); - LOAD_MODULE_SUBFUNC(active, true); - - LOAD_MODULE_SUBFUNC(properties, false); - LOAD_MODULE_SUBFUNC(pause, false); - - info->id = id; - return true; -} - -static inline const struct output_info *find_output(const char *id) +static inline const struct obs_output_info *find_output(const char *id) { size_t i; for (i = 0; i < obs->output_types.num; i++) @@ -49,7 +31,7 @@ static inline const struct output_info *find_output(const char *id) obs_output_t obs_output_create(const char *id, const char *name, obs_data_t settings) { - const struct output_info *info = find_output(id); + const struct obs_output_info *info = find_output(id); struct obs_output *output; if (!info) { @@ -58,7 +40,7 @@ obs_output_t obs_output_create(const char *id, const char *name, } output = bmalloc(sizeof(struct obs_output)); - output->callbacks = *info; + output->info = *info; output->settings = obs_data_newref(settings); output->data = info->create(output->settings, output); @@ -79,16 +61,16 @@ obs_output_t obs_output_create(const char *id, const char *name, void obs_output_destroy(obs_output_t output) { if (output) { - if (output->callbacks.active) { - if (output->callbacks.active(output->data)) - output->callbacks.stop(output->data); + if (output->info.active) { + if (output->info.active(output->data)) + output->info.stop(output->data); } pthread_mutex_lock(&obs->data.outputs_mutex); da_erase_item(obs->data.outputs, &output); pthread_mutex_unlock(&obs->data.outputs_mutex); - output->callbacks.destroy(output->data); + output->info.destroy(output->data); obs_data_release(output->settings); bfree(output->name); bfree(output); @@ -97,22 +79,22 @@ void obs_output_destroy(obs_output_t output) bool obs_output_start(obs_output_t output) { - return output->callbacks.start(output->data); + return output->info.start(output->data); } void obs_output_stop(obs_output_t output) { - output->callbacks.stop(output->data); + output->info.stop(output->data); } bool obs_output_active(obs_output_t output) { - return output->callbacks.active(output); + return output->info.active(output); } obs_properties_t obs_output_properties(const char *id, const char *locale) { - const struct output_info *info = find_output(id); + const struct obs_output_info *info = find_output(id); if (info && info->properties) return info->properties(locale); return NULL; @@ -122,8 +104,8 @@ void obs_output_update(obs_output_t output, obs_data_t settings) { obs_data_replace(&output->settings, settings); - if (output->callbacks.update) - output->callbacks.update(output->data, output->settings); + if (output->info.update) + output->info.update(output->data, output->settings); } obs_data_t obs_output_get_settings(obs_output_t output) @@ -137,11 +119,11 @@ obs_data_t obs_output_get_settings(obs_output_t output) bool obs_output_canpause(obs_output_t output) { - return output->callbacks.pause != NULL; + return output->info.pause != NULL; } void obs_output_pause(obs_output_t output) { - if (output->callbacks.pause) - output->callbacks.pause(output->data); + if (output->info.pause) + output->info.pause(output->data); } diff --git a/libobs/obs-output.h b/libobs/obs-output.h index 7051db968..ef1a66ae6 100644 --- a/libobs/obs-output.h +++ b/libobs/obs-output.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2013-2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,119 +17,26 @@ #pragma once -#include "util/c99defs.h" -#include "util/dstr.h" - -/* - * =========================================== - * Outputs - * =========================================== - * - * An output takes raw audio and/or video and processes and/or outputs it - * to a destination, whether that destination be a file, network, or other. - * - * A module with outputs needs to export these functions: - * + enum_outputs - * - * Each individual output is then exported by it's name. For example, an - * output named "myoutput" would have the following exports: - * + myoutput_getname - * + myoutput_create - * + myoutput_destroy - * + myoutput_update - * + myoutput_start - * + myoutput_stop - * + myoutput_active - * - * [and optionally] - * + myoutput_properties - * + myoutput_pause - * - * =========================================== - * Primary Exports - * =========================================== - * const char *enum_outputs(size_t idx); - * idx: index of the output. - * Return value: Output identifier name. NULL when no more available. - * - * =========================================== - * Output Exports - * =========================================== - * const char *[name]_getname(const char *locale); - * Returns the full translated name of the output type (seen by the user). - * - * --------------------------------------------------------- - * void *[name]_create(obs_data_t settings, obs_output_t output); - * Creates an output. - * - * settings: Settings of the output. - * output: pointer to main output - * Return value: Internal output pointer, or NULL if failed. - * - * --------------------------------------------------------- - * void [name]_destroy(void *data); - * Destroys the output. - * - * --------------------------------------------------------- - * void [name]_update(void *data, obs_data_t settings) - * Updates the output's settings - * - * settings: New settings of the output - * - * --------------------------------------------------------- - * bool [name]_start(void *data) - * Starts output - * - * Return value: true if successful - * - * --------------------------------------------------------- - * void [name]_stop(void *data) - * Stops output - * - * --------------------------------------------------------- - * bool [name]_active(void *data) - * Returns whether currently active or not - * - * =========================================== - * Optional Output Exports - * =========================================== - * obs_properties_t [name]_properties(const char *locale); - * Returns the properties of this particular source type, if any. - * - * --------------------------------------------------------- - * void [name]_pause(void *data) - * Pauses output. Typically only usable for local recordings. - */ - -struct obs_output; - -struct output_info { +struct obs_output_info { + /* required */ const char *id; const char *(*getname)(const char *locale); - void *(*create)(obs_data_t settings, struct obs_output *output); + void *(*create)(obs_data_t settings, obs_output_t output); void (*destroy)(void *data); - void (*update)(void *data, obs_data_t settings); - bool (*start)(void *data); void (*stop)(void *data); bool (*active)(void *data); /* optional */ + void (*update)(void *data, obs_data_t settings); + obs_properties_t (*properties)(const char *locale); void (*pause)(void *data); }; -struct obs_output { - char *name; - void *data; - struct output_info callbacks; - obs_data_t settings; -}; - -extern bool load_output_info(void *module, const char *module_name, - const char *output_name, struct output_info *info); +EXPORT void obs_register_output(const struct obs_output_info *info); diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index 7e28ea4cc..76875f221 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -81,11 +81,6 @@ static void scene_destroy(void *data) bfree(scene); } -static uint32_t scene_get_output_flags(void *data) -{ - return SOURCE_VIDEO; -} - static inline void detach_sceneitem(struct obs_scene_item *item) { if (item->prev) @@ -115,7 +110,7 @@ static inline void attach_sceneitem(struct obs_scene_item *item, } } -static void scene_video_render(void *data) +static void scene_video_render(void *data, effect_t effect) { struct obs_scene *scene = data; struct obs_scene_item *item; @@ -154,16 +149,17 @@ static uint32_t scene_getsize(void *data) return 0; } -static const struct source_info scene_info = +static const struct obs_source_info scene_info = { - .id = "scene", - .getname = scene_getname, - .create = scene_create, - .destroy = scene_destroy, - .get_output_flags = scene_get_output_flags, - .video_render = scene_video_render, - .getwidth = scene_getsize, - .getheight = scene_getsize, + .id = "scene", + .type = OBS_SOURCE_TYPE_SCENE, + .output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW, + .getname = scene_getname, + .create = scene_create, + .destroy = scene_destroy, + .video_render = scene_video_render, + .getwidth = scene_getsize, + .getheight = scene_getsize, }; obs_scene_t obs_scene_create(const char *name) @@ -188,11 +184,11 @@ obs_scene_t obs_scene_create(const char *name) } source->name = bstrdup(name); - source->type = SOURCE_SCENE; + source->type = OBS_SOURCE_TYPE_SCENE; scene->source = source; obs_source_init(source, &scene_info); - memcpy(&source->callbacks, &scene_info, sizeof(struct source_info)); + memcpy(&source->info, &scene_info, sizeof(struct obs_source_info)); return scene; } @@ -215,7 +211,7 @@ obs_source_t obs_scene_getsource(obs_scene_t scene) obs_scene_t obs_scene_fromsource(obs_source_t source) { - if (source->type != SOURCE_SCENE) + if (source->type != OBS_SOURCE_TYPE_SCENE) return NULL; return source->data; diff --git a/libobs/obs-scene.h b/libobs/obs-scene.h index d9b079459..776837af3 100644 --- a/libobs/obs-scene.h +++ b/libobs/obs-scene.h @@ -18,7 +18,7 @@ #pragma once #include "obs.h" -#include "obs-source.h" +#include "obs-internal.h" /* how obs scene! */ diff --git a/libobs/obs-service.h b/libobs/obs-service.h index ec4e92985..f70f58c39 100644 --- a/libobs/obs-service.h +++ b/libobs/obs-service.h @@ -17,15 +17,16 @@ #pragma once -struct service_data; - -struct service_info { +struct obs_service_info { + /* required */ char *id; const char *(*getname)(const char *locale); void *(*create)(obs_data_t settings, struct service_data *service); void (*destroy)(void *data); + + /* optional */ void (*update)(void *data, obs_data_t settings); /* get stream url/key */ diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 6488e14b0..a661cf382 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -26,37 +26,14 @@ static void obs_source_destroy(obs_source_t source); -bool load_source_info(void *module, const char *module_name, - const char *id, struct source_info *info) -{ - LOAD_MODULE_SUBFUNC(getname, true); - LOAD_MODULE_SUBFUNC(create, true); - LOAD_MODULE_SUBFUNC(destroy, true); - LOAD_MODULE_SUBFUNC(get_output_flags, true); - - LOAD_MODULE_SUBFUNC(properties, false); - LOAD_MODULE_SUBFUNC(update, false); - LOAD_MODULE_SUBFUNC(activate, false); - LOAD_MODULE_SUBFUNC(deactivate, false); - LOAD_MODULE_SUBFUNC(video_tick, false); - LOAD_MODULE_SUBFUNC(video_render, false); - LOAD_MODULE_SUBFUNC(getwidth, false); - LOAD_MODULE_SUBFUNC(getheight, false); - LOAD_MODULE_SUBFUNC(filter_video, false); - LOAD_MODULE_SUBFUNC(filter_audio, false); - - info->id = id; - return true; -} - -static inline const struct source_info *find_source(struct darray *list, +static inline const struct obs_source_info *find_source(struct darray *list, const char *id) { size_t i; - struct source_info *array = list->array; + struct obs_source_info *array = list->array; for (i = 0; i < list->num; i++) { - struct source_info *info = array+i; + struct obs_source_info *info = array+i; if (strcmp(info->id, id) == 0) return info; } @@ -64,16 +41,25 @@ static inline const struct source_info *find_source(struct darray *list, return NULL; } -static const struct source_info *get_source_info(enum obs_source_type type, +static const struct obs_source_info *get_source_info(enum obs_source_type type, const char *id) { struct darray *list = NULL; switch (type) { - case SOURCE_INPUT: list = &obs->input_types.da; break; - case SOURCE_FILTER: list = &obs->filter_types.da; break; - case SOURCE_TRANSITION: list = &obs->transition_types.da; break; - case SOURCE_SCENE: + case OBS_SOURCE_TYPE_INPUT: + list = &obs->input_types.da; + break; + + case OBS_SOURCE_TYPE_FILTER: + list = &obs->filter_types.da; + break; + + case OBS_SOURCE_TYPE_TRANSITION: + list = &obs->transition_types.da; + break; + + case OBS_SOURCE_TYPE_SCENE: default: blog(LOG_WARNING, "get_source_info: invalid source type"); return NULL; @@ -95,22 +81,21 @@ bool obs_source_init_handlers(struct obs_source *source) const char *obs_source_getdisplayname(enum obs_source_type type, const char *id, const char *locale) { - const struct source_info *info = get_source_info(type, id); + const struct obs_source_info *info = get_source_info(type, id); return (info != NULL) ? info->getname(locale) : NULL; } /* internal initialization */ -bool obs_source_init(struct obs_source *source, const struct source_info *info) +bool obs_source_init(struct obs_source *source, + const struct obs_source_info *info) { - uint32_t flags = info->get_output_flags(source->data); - source->refs = 1; source->volume = 1.0f; pthread_mutex_init_value(&source->filter_mutex); pthread_mutex_init_value(&source->video_mutex); pthread_mutex_init_value(&source->audio_mutex); - memcpy(&source->callbacks, info, sizeof(struct source_info)); + memcpy(&source->info, info, sizeof(struct obs_source_info)); if (pthread_mutex_init(&source->filter_mutex, NULL) != 0) return false; @@ -119,7 +104,7 @@ bool obs_source_init(struct obs_source *source, const struct source_info *info) if (pthread_mutex_init(&source->video_mutex, NULL) != 0) return false; - if (flags & SOURCE_AUDIO) { + if (info->output_flags & OBS_SOURCE_AUDIO) { source->audio_line = audio_output_createline(obs->audio.audio, source->name); if (!source->audio_line) { @@ -148,7 +133,7 @@ obs_source_t obs_source_create(enum obs_source_type type, const char *id, { struct obs_source *source; - const struct source_info *info = get_source_info(type, id); + const struct obs_source_info *info = get_source_info(type, id); if (!info) { blog(LOG_WARNING, "Source '%s' not found", id); return NULL; @@ -268,7 +253,7 @@ static void obs_source_destroy(obs_source_t source) gs_leavecontext(); if (source->data) - source->callbacks.destroy(source->data); + source->info.destroy(source->data); for (i = 0; i < MAX_AUDIO_PLANES; i++) bfree(source->audio_data.data[i]); @@ -279,6 +264,7 @@ static void obs_source_destroy(obs_source_t source) proc_handler_destroy(source->procs); signal_handler_destroy(source->signals); + texrender_destroy(source->filter_texrender); da_free(source->video_frames); da_free(source->filters); pthread_mutex_destroy(&source->filter_mutex); @@ -338,41 +324,45 @@ bool obs_source_removed(obs_source_t source) obs_properties_t obs_source_properties(enum obs_source_type type, const char *id, const char *locale) { - const struct source_info *info = get_source_info(type, id); - if (info && info->properties) - return info->properties(locale); + const struct obs_source_info *info = get_source_info(type, id); + if (info && info->get_properties) + return info->get_properties(locale); return NULL; } uint32_t obs_source_get_output_flags(obs_source_t source) { - return source->callbacks.get_output_flags(source->data); + return source->info.output_flags; } void obs_source_update(obs_source_t source, obs_data_t settings) { obs_data_replace(&source->settings, settings); - if (source->callbacks.update) - source->callbacks.update(source->data, source->settings); + if (source->info.update) + source->info.update(source->data, source->settings); } void obs_source_activate(obs_source_t source) { - if (source->callbacks.activate) - source->callbacks.activate(source->data); + if (source->info.activate) + source->info.activate(source->data); } void obs_source_deactivate(obs_source_t source) { - if (source->callbacks.deactivate) - source->callbacks.deactivate(source->data); + if (source->info.deactivate) + source->info.deactivate(source->data); } void obs_source_video_tick(obs_source_t source, float seconds) { - if (source->callbacks.video_tick) - source->callbacks.video_tick(source->data, seconds); + /* reset the filter render texture information once every frame */ + if (source->filter_texrender) + texrender_reset(source->filter_texrender); + + if (source->info.video_tick) + source->info.video_tick(source->data, seconds); } /* unless the value is 3+ hours worth of frames, this won't overflow */ @@ -399,13 +389,11 @@ static inline void reset_audio_timing(obs_source_t source, uint64_t timetamp) static inline void handle_ts_jump(obs_source_t source, uint64_t ts, uint64_t diff) { - uint32_t flags = source->callbacks.get_output_flags(source->data); - blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%lld', " "resetting audio timing", source->name, diff); /* if has video, ignore audio data until reset */ - if (flags & SOURCE_ASYNC_VIDEO) + if (source->info.output_flags & OBS_SOURCE_ASYNC_VIDEO) source->audio_reset_ref--; else reset_audio_timing(source, ts); @@ -555,7 +543,7 @@ static void obs_source_draw_texture(texture_t tex, struct source_frame *frame) sizeof(float) * 16); } - param = effect_getparambyname(effect, "diffuse"); + param = effect_getparambyname(effect, "image"); effect_settexture(effect, param, tex); gs_draw_sprite(tex, frame->flip ? GS_FLIP_V : 0, 0, 0); @@ -583,17 +571,18 @@ static inline void obs_source_render_filters(obs_source_t source) source->rendering_filter = false; } -static inline void obs_source_default_render(obs_source_t source, bool yuv) +static inline void obs_source_default_render(obs_source_t source, + bool color_matrix) { effect_t effect = obs->video.default_effect; - const char *tech_name = yuv ? "DrawMatrix" : "Draw"; + const char *tech_name = color_matrix ? "DrawMatrix" : "Draw"; technique_t tech = effect_gettechnique(effect, tech_name); size_t passes, i; passes = technique_begin(tech); for (i = 0; i < passes; i++) { technique_beginpass(tech, i); - source->callbacks.video_render(source->data); + source->info.video_render(source->data, effect); technique_endpass(tech); } technique_end(tech); @@ -601,20 +590,21 @@ static inline void obs_source_default_render(obs_source_t source, bool yuv) static inline void obs_source_main_render(obs_source_t source) { - uint32_t flags = source->callbacks.get_output_flags(source->data); + uint32_t flags = source->info.output_flags; + bool color_matrix = (flags & OBS_SOURCE_COLOR_MATRIX) != 0; bool default_effect = !source->filter_parent && source->filters.num == 0 && - (flags & SOURCE_DEFAULT_EFFECT) != 0; + (flags & OBS_SOURCE_CUSTOM_DRAW) == 0; if (default_effect) - obs_source_default_render(source, (flags & SOURCE_YUV) != 0); + obs_source_default_render(source, color_matrix); else - source->callbacks.video_render(source->data); + source->info.video_render(source->data, NULL); } void obs_source_video_render(obs_source_t source) { - if (source->callbacks.video_render) { + if (source->info.video_render) { if (source->filters.num && !source->rendering_filter) obs_source_render_filters(source); else @@ -630,15 +620,15 @@ void obs_source_video_render(obs_source_t source) uint32_t obs_source_getwidth(obs_source_t source) { - if (source->callbacks.getwidth) - return source->callbacks.getwidth(source->data); + if (source->info.getwidth) + return source->info.getwidth(source->data); return 0; } uint32_t obs_source_getheight(obs_source_t source) { - if (source->callbacks.getheight) - return source->callbacks.getheight(source->data); + if (source->info.getheight) + return source->info.getheight(source->data); return 0; } @@ -747,8 +737,8 @@ static inline struct source_frame *filter_async_video(obs_source_t source, size_t i; for (i = source->filters.num; i > 0; i--) { struct obs_source *filter = source->filters.array[i-1]; - if (filter->callbacks.filter_video) { - in = filter->callbacks.filter_video(filter->data, in); + if (filter->info.filter_video) { + in = filter->info.filter_video(filter->data, in); if (!in) return NULL; } @@ -842,8 +832,8 @@ static inline struct filtered_audio *filter_async_audio(obs_source_t source, size_t i; for (i = source->filters.num; i > 0; i--) { struct obs_source *filter = source->filters.array[i-1]; - if (filter->callbacks.filter_audio) { - in = filter->callbacks.filter_audio(filter->data, in); + if (filter->info.filter_audio) { + in = filter->info.filter_audio(filter->data, in); if (!in) return NULL; } @@ -952,11 +942,13 @@ void obs_source_output_audio(obs_source_t source, output = filter_async_audio(source, &source->audio_data); if (output) { + bool async = (flags & OBS_SOURCE_ASYNC_VIDEO) == 0; + pthread_mutex_lock(&source->audio_mutex); /* wait for video to start before outputting any audio so we * have a base for sync */ - if (source->timing_set || (flags & SOURCE_ASYNC_VIDEO) == 0) { + if (source->timing_set || async) { struct audio_data data; for (int i = 0; i < MAX_AUDIO_PLANES; i++) @@ -1091,15 +1083,15 @@ void obs_source_gettype(obs_source_t source, enum obs_source_type *type, const char **id) { if (type) *type = source->type; - if (id) *id = source->callbacks.id; + if (id) *id = source->info.id; } static inline void render_filter_bypass(obs_source_t target, effect_t effect, - uint32_t width, uint32_t height, bool yuv) + uint32_t width, uint32_t height, bool use_matrix) { - const char *tech_name = yuv ? "DrawMatrix" : "Draw"; + const char *tech_name = use_matrix ? "DrawMatrix" : "Draw"; technique_t tech = effect_gettechnique(effect, tech_name); - eparam_t diffuse = effect_getparambyname(effect, "diffuse"); + eparam_t image = effect_getparambyname(effect, "image"); size_t passes, i; passes = technique_begin(tech); @@ -1112,14 +1104,14 @@ static inline void render_filter_bypass(obs_source_t target, effect_t effect, } static inline void render_filter_tex(texture_t tex, effect_t effect, - uint32_t width, uint32_t height, bool yuv) + uint32_t width, uint32_t height, bool use_matrix) { - const char *tech_name = yuv ? "DrawMatrix" : "Draw"; + const char *tech_name = use_matrix ? "DrawMatrix" : "Draw"; technique_t tech = effect_gettechnique(effect, tech_name); - eparam_t diffuse = effect_getparambyname(effect, "diffuse"); + eparam_t image = effect_getparambyname(effect, "image"); size_t passes, i; - effect_settexture(effect, diffuse, tex); + effect_settexture(effect, image, tex); passes = technique_begin(tech); for (i = 0; i < passes; i++) { @@ -1130,8 +1122,8 @@ static inline void render_filter_tex(texture_t tex, effect_t effect, technique_end(tech); } -void obs_source_process_filter(obs_source_t filter, texrender_t texrender, - effect_t effect, uint32_t width, uint32_t height, +void obs_source_process_filter(obs_source_t filter, effect_t effect, + uint32_t width, uint32_t height, enum gs_color_format format, enum allow_direct_render allow_direct) { obs_source_t target = obs_filter_gettarget(filter); @@ -1140,8 +1132,8 @@ void obs_source_process_filter(obs_source_t filter, texrender_t texrender, uint32_t parent_flags = obs_source_get_output_flags(parent); int cx = obs_source_getwidth(target); int cy = obs_source_getheight(target); - bool yuv = (target_flags & SOURCE_YUV) != 0; - bool expects_def = (parent_flags & SOURCE_DEFAULT_EFFECT) != 0; + bool use_matrix = !!(target_flags & OBS_SOURCE_COLOR_MATRIX); + bool expects_def = !(parent_flags & OBS_SOURCE_CUSTOM_DRAW); bool can_directly = allow_direct == ALLOW_DIRECT_RENDERING; /* if the parent does not use any custom effects, and this is the last @@ -1149,23 +1141,27 @@ void obs_source_process_filter(obs_source_t filter, texrender_t texrender, * using the filter effect instead of rendering to texture to reduce * the total number of passes */ if (can_directly && expects_def && target == parent) { - render_filter_bypass(target, effect, width, height, yuv); + render_filter_bypass(target, effect, width, height, use_matrix); return; } - if (texrender_begin(texrender, cx, cy)) { + if (!filter->filter_texrender) + filter->filter_texrender = texrender_create(format, + GS_ZS_NONE); + + if (texrender_begin(filter->filter_texrender, cx, cy)) { gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f); if (expects_def && parent == target) - obs_source_default_render(parent, yuv); + obs_source_default_render(parent, use_matrix); else obs_source_video_render(target); - texrender_end(texrender); + texrender_end(filter->filter_texrender); } /* --------------------------- */ - render_filter_tex(texrender_gettexture(texrender), effect, - width, height, yuv); + render_filter_tex(texrender_gettexture(filter->filter_texrender), + effect, width, height, use_matrix); } signal_handler_t obs_source_signalhandler(obs_source_t source) diff --git a/libobs/obs-source.h b/libobs/obs-source.h index fef6c92c0..7790998f7 100644 --- a/libobs/obs-source.h +++ b/libobs/obs-source.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2013-2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,253 +17,218 @@ #pragma once -#include "util/c99defs.h" -#include "util/darray.h" -#include "util/dstr.h" -#include "util/threading.h" -#include "media-io/audio-resampler.h" -#include "callback/signal.h" -#include "callback/proc.h" +#include "obs.h" -/* - * =========================================== - * Sources - * =========================================== +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Source output flags * - * A source is literally a "source" of audio and/or video. - * - * A module with sources needs to export these functions: - * + enum_[type] - * - * [type] can be one of the following: - * + input - * + filter - * + transition - * - * input: A source used for directly playing video and/or sound. - * filter: A source that is used for filtering other sources, modifying - * the audio/video data before it is actually played. - * transition: A source used for transitioning between two different sources - * on screen. - * - * Each individual source is then exported by it's name. For example, a - * source named "mysource" would have the following exports: - * + mysource_getname - * + mysource_create - * + mysource_destroy - * + mysource_get_output_flags - * - * [and optionally] - * + mysource_properties - * + mysource_update - * + mysource_activate - * + mysource_deactivate - * + mysource_video_tick - * + mysource_video_render - * + mysource_getwidth - * + mysource_getheight - * + mysource_getparam - * + mysource_setparam - * + mysource_filtervideo - * + mysource_filteraudio - * - * =========================================== - * Primary Exports - * =========================================== - * bool enum_[type](size_t idx, const char **name); - * idx: index of the enumeration. - * name: pointer to variable that receives the type of the source - * Return value: false when no more available. - * - * =========================================== - * Source Exports - * =========================================== - * const char *[name]_getname(const char *locale); - * Returns the full name of the source type (seen by the user). - * - * --------------------------------------------------------- - * void *[name]_create(obs_data_t settings, obs_source_t source); - * Creates a source. - * - * settings: Settings of the source. - * source: pointer to main source - * Return value: Internal source pointer, or NULL if failed. - * - * --------------------------------------------------------- - * void [name]_destroy(void *data); - * Destroys the source. - * - * --------------------------------------------------------- - * uint32_t [name]_get_output_flags(void *data); - * Returns a combination of one of the following values: - * + SOURCE_VIDEO: source has video - * + SOURCE_AUDIO: source has audio - * + SOURCE_ASYNC_VIDEO: video is sent asynchronously via RAM - * + SOURCE_DEFAULT_EFFECT: source uses default effect - * + SOURCE_YUV: source is in YUV color space - * - * =========================================== - * Optional Source Exports - * =========================================== - * obs_properties_t [name]_properties(const char *locale); - * Returns the properties of this particular source type, if any. - * - * --------------------------------------------------------- - * void [name]_update(void *data, obs_data_t settings); - * Called to update the settings of the source. - * - * --------------------------------------------------------- - * void [name]_video_activate(void *data); - * Called when the source is being displayed. - * - * --------------------------------------------------------- - * void [name]_video_deactivate(void *data); - * Called when the source is no longer being displayed. - * - * --------------------------------------------------------- - * void [name]_video_tick(void *data, float seconds); - * Called each video frame with the time taken between the last and - * current frame, in seconds. - * - * --------------------------------------------------------- - * void [name]_video_render(void *data); - * Called to render the source. - * - * --------------------------------------------------------- - * uint32_t [name]_getwidth(void *data); - * Returns the width of a source, or -1 for maximum width. If you render - * video, this is required. - * - * --------------------------------------------------------- - * uint32_t [name]_getheight(void *data); - * Returns the height of a source, or -1 for maximum height. If you - * render video, this is required. - * - * --------------------------------------------------------- - * void [name]_getparam(void *data, const char *param, void *buf, - * size_t buf_size); - * Gets a source parameter value. - * - * param: Name of parameter. - * Return value: Value of parameter. - * - * --------------------------------------------------------- - * void [name]_setparam(void *data, const char *param, const void *buf, - * size_t size); - * Sets a source parameter value. - * - * param: Name of parameter. - * val: Value of parameter to set. - * - * --------------------------------------------------------- - * struct source_frame *[name]_filter_video(void *data, - * const struct source_frame *frame); - * Filters audio data. Used with audio filters. - * - * frame: Video frame data. - * returns: New video frame data (or NULL if pending) - * - * --------------------------------------------------------- - * struct filter_audio [name]_filter_audio(void *data, - * struct filter_audio *audio); - * Filters video data. Used with async video data. - * - * audio: Audio data. - * reutrns New audio data (or NULL if pending) + * These flags determine what type of data the source outputs and expects. + * @{ */ -struct obs_source; +/** + * Source has video. + * + * Unless SOURCE_ASYNC_VIDEO is specified, the source must include the + * video_render callback in the source definition structure. + */ +#define OBS_SOURCE_VIDEO (1<<0) -struct source_info { +/** + * Source has audio. + * + * Use the obs_source_output_audio function to pass raw audio data, which will + * be automatically converted and uploaded. If used with SOURCE_ASYNC_VIDEO, + * audio will automatically be synced up to the video output. + */ +#define OBS_SOURCE_AUDIO (1<<1) + +/** + * Source passes raw video data via RAM. + * + * Use the obs_source_output_video function to pass raw video data, which will + * be automatically uploaded at the specified timestamp. + * + * If this flag is specified, it is not necessary to include the video_render + * callback. However, if you wish to use that function as well, you must call + * obs_source_getframe to get the current frame data, and + * obs_source_releaseframe to release the data when complete. + */ +#define OBS_SOURCE_ASYNC_VIDEO ((1<<2) | OBS_SOURCE_VIDEO) + +/** + * Source uses custom drawing, rather than a default effect. + * + * If this flag is specified, the video_render callback will pass a NULL + * effect, and effect-based filters will not use direct rendering. + */ +#define OBS_SOURCE_CUSTOM_DRAW (1<<3) + +/** + * Source uses a color matrix (usually YUV sources). + * + * When this is used, the video_render callback will automatically assign a + * 4x4 YUV->RGB matrix to the "color_matrix" parameter of the effect, or it can + * be overwritten with a custom value. + */ +#define OBS_SOURCE_COLOR_MATRIX (1<<4) + +/** @} */ + +/** + * Source definition structure + */ +struct obs_source_info { + /* ----------------------------------------------------------------- */ + /* Required implementation*/ + + /** Unique string identifier for the source */ const char *id; - /* ----------------------------------------------------------------- */ - /* required implementations */ + /** + * Type of source. + * + * OBS_SOURCE_INPUT for input sources, + * OBS_SOURCE_FILTER for filter sources, and + * OBS_SOURCE_TRANSITION for transition sources. + */ + enum obs_source_type type; + /** Source output flags */ + uint32_t output_flags; + + /** + * Get the translated name of the source type + * + * @param locale The locale to translate with + * @return The translated name of the source type + */ const char *(*getname)(const char *locale); + /** + * Creates the source data for the source + * + * @param settings Settings to initialize the source with + * @param source Source that this data is assoicated with + * @return The data associated with this source + */ void *(*create)(obs_data_t settings, obs_source_t source); + + /** Destroys the private data for the source */ void (*destroy)(void *data); - uint32_t (*get_output_flags)(void *data); - /* ----------------------------------------------------------------- */ - /* optional implementations */ + /* Optional implementation */ - obs_properties_t (*properties)(const char *locale); + /** + * Gets the property information of this source + * + * @param locale The locale to translate with + * @return The properties data. Caller is responsible for + * freeing the data with obs_properties_destroy + */ + obs_properties_t (*get_properties)(const char *locale); + /** + * Updates the settings for this source + * + * @param data Source data + * @param settings New settings for this source + */ void (*update)(void *data, obs_data_t settings); + /** Called when the source has been activated */ void (*activate)(void *data); + + /** + * Called when the source has been deactivated (no longer being + * played/displayed) + */ void (*deactivate)(void *data); + /** + * Called each video frame with the time elapsed + * + * @param data Source data + * @param seconds Seconds elapsed since the last frame + */ void (*video_tick)(void *data, float seconds); - void (*video_render)(void *data); + + /** + * Called when rendering the source with the graphics subsystem. + * + * If this is an input/transition source, this is called to draw the + * source texture with the graphics subsystem using the specified + * effect. + * + * If this is a filter source, it wraps source draw calls (for + * example applying a custom effect with custom parameters to a + * source). In this case, it's highly recommended to use the + * obs_source_process_filter function to automatically handle + * effect-based filter processing. However, you can implement custom + * draw handling as desired as well. + * + * If the source output flags do not include SOURCE_CUSTOM_DRAW, all + * a source needs to do is set the "output" parameter of the effect to + * the desired texture, and then draw. If the output flags include + * SOURCE_COLOR_MATRIX, you may optionally set the the "color_matrix" + * parameter of the effect to a custom 4x4 conversion matrix (by + * default it will be set to an YUV->RGB conversion matrix) + * + * @param data Source data + * @param effect Effect to be used with this source. If the source + * output flags include SOURCE_CUSTOM_DRAW, this will + * be NULL, and the source is expected to process with + * an effect manually. + */ + void (*video_render)(void *data, effect_t effect); + + /** @return The width of the source */ uint32_t (*getwidth)(void *data); + + /** @return The height of the source */ uint32_t (*getheight)(void *data); + /** + * Called to filter raw async video data. + * + * @note This function is only used with filter sources. + * + * @param data Source data + * @param frame Video frame to filter + * @return New video frame data. This can defer video data to + * be drawn later if time is needed for processing + */ struct source_frame *(*filter_video)(void *data, const struct source_frame *frame); + + /** + * Called to filter raw audio data. + * + * @note This function is only used with filter sources. + * + * @param data Source data + * @param audio Audio data to filter. + * @return Modified or new audio data. You can directly modify + * the data passed and return it, or you can defer audio + * data for later if time is needed for processing. + */ struct filtered_audio *(*filter_audio)(void *data, struct filtered_audio *audio); }; -struct obs_source { - volatile int refs; +/** + * Regsiters a source definition to the current obs context. This should be + * used in obs_module_load. + * + * @param info Pointer to the source definition structure + */ +EXPORT void obs_register_source(const struct obs_source_info *info); - /* source-specific data */ - char *name; /* user-defined name */ - enum obs_source_type type; - obs_data_t settings; - void *data; - struct source_info callbacks; - - signal_handler_t signals; - proc_handler_t procs; - - /* used to indicate that the source has been removed and all - * references to it should be released (not exactly how I would prefer - * to handle things but it's the best option) */ - bool removed; - - /* timing (if video is present, is based upon video) */ - volatile bool timing_set; - volatile uint64_t timing_adjust; - volatile int audio_reset_ref; - uint64_t next_audio_ts_min; - uint64_t last_frame_ts; - uint64_t last_sys_timestamp; - - /* audio */ - bool audio_failed; - struct resample_info sample_info; - audio_resampler_t resampler; - audio_line_t audio_line; - pthread_mutex_t audio_mutex; - struct filtered_audio audio_data; - size_t audio_storage_size; - float volume; - - /* async video data */ - texture_t output_texture; - DARRAY(struct source_frame*) video_frames; - pthread_mutex_t video_mutex; - - /* filters */ - struct obs_source *filter_parent; - struct obs_source *filter_target; - DARRAY(struct obs_source*) filters; - pthread_mutex_t filter_mutex; - bool rendering_filter; -}; - -extern bool load_source_info(void *module, const char *module_name, - const char *source_name, struct source_info *info); - -bool obs_source_init_handlers(struct obs_source *source); -extern bool obs_source_init(struct obs_source *source, - const struct source_info *info); - -extern void obs_source_activate(obs_source_t source); -extern void obs_source_deactivate(obs_source_t source); -extern void obs_source_video_tick(obs_source_t source, float seconds); +#ifdef __cplusplus +} +#endif diff --git a/libobs/obs-ui.h b/libobs/obs-ui.h index ee32087a7..111f088ab 100644 --- a/libobs/obs-ui.h +++ b/libobs/obs-ui.h @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (C) 2013 by Hugh Bailey + Copyright (C) 2013-2014 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,138 +23,132 @@ extern "C" { #endif -struct obs_modal_ui { - const char *name; - const char *task; - const char *target; - bool (*callback)(void *object, void *ui_data); -}; - -struct obs_modeless_ui { - const char *name; - const char *task; - const char *target; - void *(*callback)(void *object, void *ui_data); -}; - -/* - * =========================================== - * Module UI calls - * =========================================== +/** + * @file * - * Modules can specify custom user-interface-specific exports. UI exports + * Modules can specify custom user-interface-specific exports. UI functions * can be within the same library as the actual core logic, or separated in to * different modules to split up UI logic and core module logic. * * The reasoning for this is to allow for custom user interface of differing * toolkits or for automatically generated user interface, or to simply allow * separation of UI code from core code (which may often be in differing - * languages) - * - * A module with UI calls needs to export one or both of these functions: - * + enum_modal_ui - * + enum_modeless_ui - * - * The enum_ui function provides an obs_ui_info structure for each - * input/output/etc. Modeless UI should be exported enum_modeless_ui. For - * example, to export Qt-specific configuration functions, the values given to - * enum_modal_ui might look something like this: - * - * struct obs_modal_ui ui_list[] = { - * {"mysource", "config", "qt", mysource_config}, - * {"myoutput", "config", "qt", myoutput_config}, - * {"myencoder", "config", "qt", myenoder_config} - * }; - * - * 'qt' could be replaced with 'wx' or something similar if using wxWidgets, - * or 'win32' if using bare windows API. It could also specify a custom name - * if desired (use with discretion). - * - * =========================================== - * Primary Exports - * =========================================== - * bool enum_modal_ui(size_t idx, struct obs_modal_ui *ui_info); - * - * idx: index of the enumeration - * ui_info: pointer to the ui data for this enumeration - * Return value: false when no more available. - * - * --------------------------------------------------------- - * bool enum_modeless_ui(size_t idx, struct obs_modeless_ui *ui_info); - * - * idx: index of the enumeration - * ui_info: pointer to the ui data for this enumeration - * Return value: false when no more available. - * - * =========================================== - * Modal UI Callback - * =========================================== - * bool modal_callback(void *object, void *ui_data); - * - * The 'object' variable points to the input/output/encoder/etc. The - * 'ui_data' varaible points to the UI parent or UI-specific data to be used - * with the custom user interface. - * - * What 'ui_data' points to differs depending on the target, and you should - * use discretion and consistency when using this variable to relay - * information to the UI function. For example, it would be ideal to have - * 'ui_data' point to a parent, QWidget for Qt, or a wxWindow for wxWidgets, - * etc., though it's up to the discretion of the developer to define that - * value. Because of the nature of void pointers, discretion and consistency - * is advised. - * - * =========================================== - * Modeless UI Callback - * =========================================== - * void *modeless_callback(void *data, void *ui_data); - * - * Modeless UI calls return immediately, and typically are supposed to return - * a pointer or handle to the specific UI object that was created. For - * example, a Qt object would ideally return a pointer to a QWidget. Again, - * discretion and consistency is advised for the return value. + * languages). */ +/** Modal UI definition structure */ +struct obs_modal_ui { + const char *id; /**< Identifier associated with this UI */ + const char *task; /**< Task of the UI */ + const char *target; /**< UI target (UI toolkit or program name) */ + + /** + * Callback to execute modal interface. + * + * The @b object variable points to the input/output/encoder/etc. The + * @b ui_data varaible points to the UI parent or UI-specific data to + * be used with the custom user interface. + * + * What @b ui_data points to differs depending on the target, and you + * should use discretion and consistency when using this variable to + * relay information to the UI function. For example, it would be + * ideal to have @b ui_data point to a parent, QWidget for Qt, or a + * wxWindow for wxWidgets, etc., though it's up to the discretion of + * the developer to define that value. Because of the nature of void + * pointers, discretion and consistency is advised. + * + * @param object Pointer/handle to the data associated with this + * call. + * @param ui_data UI data to pass associated with this specific + * target, if any. + * @return @b true if user completed the task, or + * @b false if user cancelled the task. + */ + bool (*exec)(void *object, void *ui_data); +}; + /** - * =========================================== - * obs_exec_ui - * =========================================== - * Requests modal UI to be displayed. Returns when user is complete. + * Regsiters a modal UI definition to the current obs context. This should be + * used in obs_module_load. * - * name: Name of the input/output/etc type that UI was requested for - * task: Task of the user interface (usually "config") - * target: Desired target (i.e. "qt", "wx", "gtk3", "win32", etc) - * data: Pointer to the obs input/output/etc - * ui_data: UI-specific data, usually a parent pointer/handle (if any) - * - * Return value: OBS_UI_SUCCESS if the UI was successful - * OBS_UI_CANCEL if the UI was cancelled by the user - * OBS_UI_NOTFOUND if the UI callback was not found + * @param info Pointer to the modal definition structure */ +EXPORT void obs_register_modal_ui(const struct obs_modal_ui *info); + +/* ------------------------------------------------------------------------- */ + +/** Modeless UI definition structure */ +struct obs_modeless_ui { + const char *id; /**< Identifier associated with this UI */ + const char *task; /**< Task of the UI */ + const char *target; /**< UI target (UI toolkit or program name) */ + + /** + * Callback to create modeless interface. + * + * This function is almost identical to the modal exec function, + * except modeless UI calls return immediately, and typically are + * supposed to return a pointer or handle to the specific UI object + * that was created. For example, a Qt object would ideally return a + * pointer to a QWidget. Again, discretion and consistency is advised + * for the return value. + * + * @param object Pointer/handle to the data associated with this + * call. + * @param ui_data UI data to pass associated with this specific + * target, if any. + * @return Pointer/handle to the modeless UI associated with + * the specific target. + */ + void *(*create)(void *object, void *ui_data); +}; + +/** + * Registers a modeless UI definition to the current obs context. This should + * be used in obs_module_load. + * + * @param info Pointer to the modal definition structure + */ +EXPORT void obs_register_modeless_ui(const struct obs_modeless_ui *info); + +/* ------------------------------------------------------------------------- */ + #define OBS_UI_SUCCESS 0 #define OBS_UI_CANCEL -1 #define OBS_UI_NOTFOUND -2 -EXPORT int obs_exec_ui(const char *name, const char *task, const char *target, +/** + * Requests modal UI to be displayed. Returns when user is complete. + * + * @param name Name of the input/output/etc type that UI was requested for + * @param task Task of the user interface (usually "config") + * @param target Desired target (i.e. "qt", "wx", "gtk3", "win32", etc) + * @param data Pointer to the obs input/output/etc + * @param ui_data UI-specific data, usually a parent pointer/handle (if any) + * + * @return OBS_UI_SUCCESS if the UI was successful, + * OBS_UI_CANCEL if the UI was cancelled by the user, or + * OBS_UI_NOTFOUND if the UI callback was not found + */ +EXPORT int obs_exec_ui(const char *id, const char *task, const char *target, void *data, void *ui_data); /** - * =========================================== - * obs_create_ui - * =========================================== * Requests modeless UI to be created. Returns immediately. * - * name: Name of the input/output/etc type that UI was requested for - * task: Task of the user interface - * target: Desired target (i.e. "qt", "wx", "gtk3", "win32", etc) - * data: Pointer to the obs input/output/etc - * ui_data: UI-specific data, usually a parent pointer/handle (if any) + * @param name Name of the input/output/etc type that UI was requested for + * @param task Task of the user interface + * @param target Desired target (i.e. "qt", "wx", "gtk3", "win32", etc) + * @param data Pointer to the obs input/output/etc + * @param ui_data UI-specific data, usually a parent pointer/handle (if any) * - * Return value: Pointer to the target-specific modeless object, or NULL if - * not found or failed. + * @return Pointer/handle to the target-specific modeless object, or + * NULL if not found or failed. */ -EXPORT void *obs_create_ui(const char *name, const char *task, +EXPORT void *obs_create_ui(const char *id, const char *task, const char *target, void *data, void *ui_data); + #ifdef __cplusplus } #endif diff --git a/libobs/obs-video.c b/libobs/obs-video.c index a88490dac..dfd2f1cb2 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -164,7 +164,7 @@ static inline void render_output_texture(struct obs_core_video *video, /* TODO: replace with actual downscalers or unpackers */ effect_t effect = video->default_effect; technique_t tech = effect_gettechnique(effect, "DrawMatrix"); - eparam_t diffuse = effect_getparambyname(effect, "diffuse"); + eparam_t image = effect_getparambyname(effect, "image"); eparam_t matrix = effect_getparambyname(effect, "color_matrix"); size_t passes, i; @@ -184,7 +184,7 @@ static inline void render_output_texture(struct obs_core_video *video, }; effect_setval(effect, matrix, mat_val, sizeof(mat_val)); - effect_settexture(effect, diffuse, texture); + effect_settexture(effect, image, texture); passes = technique_begin(tech); for (i = 0; i < passes; i++) { diff --git a/libobs/obs.c b/libobs/obs.c index a45d05546..3f51ab565 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -19,7 +19,6 @@ #include "obs.h" #include "obs-internal.h" -#include "obs-module.h" struct obs_core *obs = NULL; @@ -332,8 +331,8 @@ void obs_shutdown(void) da_free(obs->transition_types); da_free(obs->output_types); da_free(obs->service_types); - da_free(obs->ui_modal_callbacks); - da_free(obs->ui_modeless_callbacks); + da_free(obs->modal_ui_callbacks); + da_free(obs->modeless_ui_callbacks); obs_free_data(); obs_free_video(); @@ -463,13 +462,13 @@ video_t obs_video(void) } /* TODO: optimize this later so it's not just O(N) string lookups */ -static inline struct obs_modal_ui *get_modal_ui_callback(const char *name, +static inline struct obs_modal_ui *get_modal_ui_callback(const char *id, const char *task, const char *target) { - for (size_t i = 0; i < obs->ui_modal_callbacks.num; i++) { - struct obs_modal_ui *callback = obs->ui_modal_callbacks.array+i; + for (size_t i = 0; i < obs->modal_ui_callbacks.num; i++) { + struct obs_modal_ui *callback = obs->modal_ui_callbacks.array+i; - if (strcmp(callback->name, name) == 0 && + if (strcmp(callback->id, id) == 0 && strcmp(callback->task, task) == 0 && strcmp(callback->target, target) == 0) return callback; @@ -478,14 +477,14 @@ static inline struct obs_modal_ui *get_modal_ui_callback(const char *name, return NULL; } -static inline struct obs_modeless_ui *get_modeless_ui_callback(const char *name, +static inline struct obs_modeless_ui *get_modeless_ui_callback(const char *id, const char *task, const char *target) { - for (size_t i = 0; i < obs->ui_modeless_callbacks.num; i++) { + for (size_t i = 0; i < obs->modeless_ui_callbacks.num; i++) { struct obs_modeless_ui *callback; - callback = obs->ui_modeless_callbacks.array+i; + callback = obs->modeless_ui_callbacks.array+i; - if (strcmp(callback->name, name) == 0 && + if (strcmp(callback->id, id) == 0 && strcmp(callback->task, task) == 0 && strcmp(callback->target, target) == 0) return callback; @@ -502,7 +501,7 @@ int obs_exec_ui(const char *name, const char *task, const char *target, callback = get_modal_ui_callback(name, task, target); if (callback) { - bool success = callback->callback(data, ui_data); + bool success = callback->exec(data, ui_data); errorcode = success ? OBS_UI_SUCCESS : OBS_UI_CANCEL; } @@ -515,7 +514,7 @@ void *obs_create_ui(const char *name, const char *task, const char *target, struct obs_modeless_ui *callback; callback = get_modeless_ui_callback(name, task, target); - return callback ? callback->callback(data, ui_data) : NULL; + return callback ? callback->create(data, ui_data) : NULL; } bool obs_add_source(obs_source_t source) diff --git a/libobs/obs.h b/libobs/obs.h index 93f1f6f0b..04b3165f8 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -26,10 +26,31 @@ #include "callback/signal.h" #include "callback/proc.h" +/* opaque types */ +struct obs_display; +struct obs_source; +struct obs_scene; +struct obs_scene_item; +struct obs_output; +struct obs_encoder; +struct obs_service; + +typedef struct obs_display *obs_display_t; +typedef struct obs_source *obs_source_t; +typedef struct obs_scene *obs_scene_t; +typedef struct obs_scene_item *obs_sceneitem_t; +typedef struct obs_output *obs_output_t; +typedef struct obs_encoder *obs_encoder_t; +typedef struct obs_service *obs_service_t; + #include "obs-defs.h" #include "obs-data.h" #include "obs-ui.h" #include "obs-properties.h" +#include "obs-source.h" +#include "obs-encoder.h" +#include "obs-output.h" +#include "obs-service.h" /* * Main libobs header used by applications. @@ -47,10 +68,11 @@ extern "C" { LIBOBS_API_MINOR_VER) enum obs_source_type { - SOURCE_INPUT, - SOURCE_FILTER, - SOURCE_TRANSITION, - SOURCE_SCENE + OBS_SOURCE_TYPE_INPUT, + OBS_SOURCE_TYPE_FILTER, + OBS_SOURCE_TYPE_TRANSITION, + + OBS_SOURCE_TYPE_SCENE }; /* used for changing the order of items (for example, filters in a source, @@ -142,23 +164,6 @@ struct encoder_packet { enum packet_priority priority; }; -/* opaque types */ -struct obs_display; -struct obs_source; -struct obs_scene; -struct obs_scene_item; -struct obs_output; -struct obs_encoder; -struct obs_service; - -typedef struct obs_display *obs_display_t; -typedef struct obs_source *obs_source_t; -typedef struct obs_scene *obs_scene_t; -typedef struct obs_scene_item *obs_sceneitem_t; -typedef struct obs_output *obs_output_t; -typedef struct obs_encoder *obs_encoder_t; -typedef struct obs_service *obs_service_t; - /* ------------------------------------------------------------------------- */ /* OBS context */ @@ -433,9 +438,8 @@ EXPORT void obs_source_releaseframe(obs_source_t source, struct source_frame *frame); /** Default RGB filter handler for generic effect filters */ -EXPORT void obs_source_process_filter(obs_source_t filter, - texrender_t texrender, effect_t effect, - uint32_t width, uint32_t height, +EXPORT void obs_source_process_filter(obs_source_t filter, effect_t effect, + uint32_t width, uint32_t height, enum gs_color_format format, enum allow_direct_render allow_direct); diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 35e37928c..c9e59bf9c 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -184,7 +184,7 @@ void OBSBasic::UpdateSceneSelection(OBSSource source) obs_source_type type; obs_source_gettype(source, &type, NULL); - if (type != SOURCE_SCENE) + if (type != OBS_SOURCE_TYPE_SCENE) return; obs_scene_t scene = obs_scene_fromsource(source); @@ -232,7 +232,7 @@ void OBSBasic::SourceAdded(void *data, calldata_t params) obs_source_type type; obs_source_gettype(source, &type, NULL); - if (type == SOURCE_SCENE) + if (type == OBS_SOURCE_TYPE_SCENE) QMetaObject::invokeMethod(static_cast(data), "AddScene", Q_ARG(OBSSource, OBSSource(source))); @@ -245,7 +245,7 @@ void OBSBasic::SourceRemoved(void *data, calldata_t params) obs_source_type type; obs_source_gettype(source, &type, NULL); - if (type == SOURCE_SCENE) + if (type == OBS_SOURCE_TYPE_SCENE) QMetaObject::invokeMethod(static_cast(data), "RemoveScene", Q_ARG(OBSSource, OBSSource(source))); @@ -474,8 +474,8 @@ void OBSBasic::AddSource(obs_scene_t scene, const char *id) } if (success) { - obs_source_t source = obs_source_create(SOURCE_INPUT, id, - name.c_str(), NULL); + obs_source_t source = obs_source_create(OBS_SOURCE_TYPE_INPUT, + id, name.c_str(), NULL); sourceSceneRefs[source] = 0; @@ -497,7 +497,8 @@ void OBSBasic::AddSourcePopupMenu(const QPoint &pos) QMenu popup; while (obs_enum_input_types(idx++, &type)) { - const char *name = obs_source_getdisplayname(SOURCE_INPUT, + const char *name = obs_source_getdisplayname( + OBS_SOURCE_TYPE_INPUT, type, App()->GetLocale()); QAction *popupItem = new QAction(QT_UTF8(name), this); diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt index 16466b675..8c27e6a9e 100644 --- a/plugins/obs-ffmpeg/CMakeLists.txt +++ b/plugins/obs-ffmpeg/CMakeLists.txt @@ -19,13 +19,9 @@ add_definitions(${Libswresample_DEFINITIONS}) set(obs-ffmpeg_SOURCES obs-ffmpeg.c obs-ffmpeg-output.c) - -set(obs-ffmpeg_HEADERS - obs-ffmpeg-output.h) add_library(obs-ffmpeg MODULE - ${obs-ffmpeg_SOURCES} - ${obs-ffmpeg_HEADERS}) + ${obs-ffmpeg_SOURCES}) target_link_libraries(obs-ffmpeg libobs ${Libavcodec_LIBRARIES} diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index f744b39ba..af29d10f3 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -16,7 +16,41 @@ ******************************************************************************/ #include -#include "obs-ffmpeg-output.h" +#include + +#include +#include + +struct ffmpeg_data { + AVStream *video; + AVStream *audio; + AVCodec *acodec; + AVCodec *vcodec; + AVFormatContext *output; + struct SwsContext *swscale; + + AVPicture dst_picture; + AVFrame *vframe; + int frame_size; + int total_frames; + + struct circlebuf excess_frames[MAX_AUDIO_PLANES]; + uint8_t *samples[MAX_AUDIO_PLANES]; + AVFrame *aframe; + int total_samples; + + const char *filename_test; + + bool initialized; +}; + +struct ffmpeg_output { + obs_output_t output; + volatile bool active; + struct ffmpeg_data ff_data; +}; + +/* ------------------------------------------------------------------------- */ /* TODO: remove these later */ #define SPS_TODO 44100 @@ -319,29 +353,29 @@ fail: /* ------------------------------------------------------------------------- */ -const char *ffmpeg_output_getname(const char *locale) +static const char *ffmpeg_output_getname(const char *locale) { - /* TODO: translation */ return "FFmpeg file output"; } -void test_callback(void *param, int bla, const char *format, va_list args) +static void ffmpeg_log_callback(void *param, int bla, const char *format, + va_list args) { blogva(LOG_INFO, format, args); } -struct ffmpeg_output *ffmpeg_output_create(obs_data_t settings, +static struct ffmpeg_output *ffmpeg_output_create(obs_data_t settings, obs_output_t output) { struct ffmpeg_output *data = bzalloc(sizeof(struct ffmpeg_output)); data->output = output; - av_log_set_callback(test_callback); + av_log_set_callback(ffmpeg_log_callback); return data; } -void ffmpeg_output_destroy(struct ffmpeg_output *data) +static void ffmpeg_output_destroy(struct ffmpeg_output *data) { if (data) { if (data->active) @@ -350,7 +384,8 @@ void ffmpeg_output_destroy(struct ffmpeg_output *data) } } -void ffmpeg_output_update(struct ffmpeg_output *data, obs_data_t settings) +static void ffmpeg_output_update(struct ffmpeg_output *data, + obs_data_t settings) { } @@ -457,7 +492,7 @@ static inline void encode_audio(struct ffmpeg_data *data, ret = avcodec_fill_audio_frame(data->aframe, context->channels, context->sample_fmt, data->samples[0], - total_size, 1); + (int)total_size, 1); if (ret < 0) { blog(LOG_ERROR, "receive_audio: avcodec_fill_audio_frame " "failed: %s", av_err2str(ret)); @@ -513,7 +548,7 @@ static void receive_audio(void *param, const struct audio_data *frame) } } -bool ffmpeg_output_start(struct ffmpeg_output *data) +static bool ffmpeg_output_start(struct ffmpeg_output *data) { video_t video = obs_video(); audio_t audio = obs_audio(); @@ -552,7 +587,7 @@ bool ffmpeg_output_start(struct ffmpeg_output *data) return true; } -void ffmpeg_output_stop(struct ffmpeg_output *data) +static void ffmpeg_output_stop(struct ffmpeg_output *data) { if (data->active) { data->active = false; @@ -562,7 +597,18 @@ void ffmpeg_output_stop(struct ffmpeg_output *data) } } -bool ffmpeg_output_active(struct ffmpeg_output *data) +static bool ffmpeg_output_active(struct ffmpeg_output *data) { return data->active; } + +struct obs_output_info ffmpeg_output = { + .id = "ffmpeg_output", + .getname = ffmpeg_output_getname, + .create = ffmpeg_output_create, + .destroy = ffmpeg_output_destroy, + .update = ffmpeg_output_update, + .start = ffmpeg_output_start, + .stop = ffmpeg_output_stop, + .active = ffmpeg_output_active +}; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.h b/plugins/obs-ffmpeg/obs-ffmpeg-output.h deleted file mode 100644 index 34029b25c..000000000 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.h +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - Copyright (C) 2013 by Hugh Bailey - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -******************************************************************************/ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -struct ffmpeg_data { - AVStream *video; - AVStream *audio; - AVCodec *acodec; - AVCodec *vcodec; - AVFormatContext *output; - struct SwsContext *swscale; - - AVPicture dst_picture; - AVFrame *vframe; - int frame_size; - int total_frames; - - struct circlebuf excess_frames[MAX_AUDIO_PLANES]; - uint8_t *samples[MAX_AUDIO_PLANES]; - AVFrame *aframe; - int total_samples; - - const char *filename_test; - - bool initialized; -}; - -struct ffmpeg_output { - obs_output_t output; - volatile bool active; - struct ffmpeg_data ff_data; -}; - -EXPORT const char *ffmpeg_output_getname(const char *locale); - -EXPORT struct ffmpeg_output *ffmpeg_output_create(obs_data_t settings, - obs_output_t output); -EXPORT void ffmpeg_output_destroy(struct ffmpeg_output *data); - -EXPORT void ffmpeg_output_update(struct ffmpeg_output *data, - obs_data_t settings); - -EXPORT bool ffmpeg_output_start(struct ffmpeg_output *data); -EXPORT void ffmpeg_output_stop(struct ffmpeg_output *data); - -EXPORT bool ffmpeg_output_active(struct ffmpeg_output *data); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c index b983c4670..edfd3adce 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg.c @@ -1,21 +1,11 @@ -#include -#include +#include -EXPORT bool enum_outputs(size_t idx, const char **name); -EXPORT uint32_t module_version(uint32_t in_version); +OBS_DECLARE_MODULE() -static const char *outputs[] = {"ffmpeg_output"}; +extern struct obs_output_info ffmpeg_output; -uint32_t module_version(uint32_t in_version) +bool obs_module_load(uint32_t obs_version) { - return LIBOBS_API_VER; -} - -bool enum_outputs(size_t idx, const char **name) -{ - if (idx >= sizeof(outputs)/sizeof(const char*)) - return false; - - *name = outputs[idx]; + obs_register_output(&ffmpeg_output); return true; } diff --git a/test/osx/test.mm b/test/osx/test.mm index 7fe6bdad3..3885260d8 100644 --- a/test/osx/test.mm +++ b/test/osx/test.mm @@ -148,14 +148,14 @@ static void test() /* ------------------------------------------------------ */ /* create source */ - SourceContext source{obs_source_create(SOURCE_INPUT, + SourceContext source{obs_source_create(OBS_SOURCE_INPUT, "random", "a test source", NULL)}; if (!source) throw "Couldn't create random test source"; /* ------------------------------------------------------ */ /* create filter */ - SourceContext filter{obs_source_create(SOURCE_FILTER, + SourceContext filter{obs_source_create(OBS_SOURCE_FILTER, "test", "a test filter", NULL)}; if (!filter) throw "Couldn't create test filter"; diff --git a/test/test-input/CMakeLists.txt b/test/test-input/CMakeLists.txt index cf01e5d7f..2b07e76f4 100644 --- a/test/test-input/CMakeLists.txt +++ b/test/test-input/CMakeLists.txt @@ -30,15 +30,8 @@ set(test-input_SOURCES test-sinewave.c test-random.c) -set(test-input_HEADERS - test-filter.h - test-input-exports.h - test-random.h - test-sinewave.h) - add_library(test-input MODULE - ${test-input_SOURCES} - ${test-input_HEADERS}) + ${test-input_SOURCES}) target_link_libraries(test-input ${test-input_PLATFORM_DEPS} diff --git a/test/test-input/test-desktop.h b/test/test-input/test-desktop.h deleted file mode 100644 index 5698b316a..000000000 --- a/test/test-input/test-desktop.h +++ /dev/null @@ -1,41 +0,0 @@ -#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; - - texture_t tex; - pthread_mutex_t mutex; - IOSurfaceRef current, prev; -}; - -EXPORT const char *osx_desktop_test_getname(const char *locale); - -EXPORT struct desktop_tex *osx_desktop_test_create(const char *settings, - obs_source_t source); -EXPORT void osx_desktop_test_destroy(struct desktop_tex *rt); -EXPORT uint32_t osx_desktop_test_get_output_flags(struct desktop_tex *rt); -EXPORT void osx_desktop_test_video_tick(struct desktop_tex *rt, float dt); - -EXPORT void osx_desktop_test_video_render(struct desktop_tex *rt, - obs_source_t filter_target); - -EXPORT uint32_t osx_desktop_test_getwidth(struct desktop_tex *rt); -EXPORT uint32_t osx_desktop_test_getheight(struct desktop_tex *rt); - -#ifdef __cplusplus -} -#endif diff --git a/test/test-input/test-desktop.m b/test/test-input/test-desktop.m index 659cdce4d..c7378d4e3 100644 --- a/test/test-input/test-desktop.m +++ b/test/test-input/test-desktop.m @@ -1,25 +1,60 @@ #include -#include "test-desktop.h" +#include +#include +#import #import #import #import #import #import #import -#include +struct desktop_tex { + samplerstate_t sampler; + effect_t whatever; -const char *osx_desktop_test_getname(const char *locale) -{ - return "OSX Monitor Capture"; -} + CGDisplayStreamRef disp; + uint32_t width, height; + + texture_t tex; + pthread_mutex_t mutex; + IOSurfaceRef current, prev; +}; static IOSurfaceRef current = NULL, prev = NULL; static pthread_mutex_t c_mutex; -struct desktop_tex *osx_desktop_test_create(const char *settings, +static const char *osx_desktop_test_getname(const char *locale) +{ + return "OSX Monitor Capture"; +} + +static void osx_desktop_test_destroy(struct desktop_tex *rt) +{ + if (rt) { + pthread_mutex_lock(&rt->mutex); + gs_entercontext(obs_graphics()); + + if (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); + } +} + +static struct desktop_tex *osx_desktop_test_create(const char *settings, obs_source_t source) { struct desktop_tex *rt = bzalloc(sizeof(struct desktop_tex)); @@ -101,35 +136,7 @@ struct desktop_tex *osx_desktop_test_create(const char *settings, return rt; } -void osx_desktop_test_destroy(struct desktop_tex *rt) -{ - if (rt) { - pthread_mutex_lock(&rt->mutex); - gs_entercontext(obs_graphics()); - - if (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); - } -} - -uint32_t osx_desktop_test_get_output_flags(struct desktop_tex *rt) -{ - return SOURCE_VIDEO; -} - -void osx_desktop_test_video_render(struct desktop_tex *rt, +static void osx_desktop_test_video_render(struct desktop_tex *rt, obs_source_t filter_target) { pthread_mutex_lock(&rt->mutex); @@ -161,12 +168,24 @@ fail: pthread_mutex_unlock(&rt->mutex); } -uint32_t osx_desktop_test_getwidth(struct desktop_tex *rt) +static uint32_t osx_desktop_test_getwidth(struct desktop_tex *rt) { return rt->width; } -uint32_t osx_desktop_test_getheight(struct desktop_tex *rt) +static uint32_t osx_desktop_test_getheight(struct desktop_tex *rt) { return rt->height; } + +struct obs_source_info osx_desktop = { + .id = "osx_desktop", + .type = OBS_SOURCE_TYPE_INPUT, + .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_video_render, + .getwidth = osx_desktop_test_getwidth, + .getheight = osx_desktop_test_getheight, +}; diff --git a/test/test-input/test-filter.c b/test/test-input/test-filter.c index 8be999066..de7fca27c 100644 --- a/test/test-input/test-filter.c +++ b/test/test-input/test-filter.c @@ -1,11 +1,29 @@ -#include "test-filter.h" +#include -const char *test_getname(const char *locale) +struct test_filter { + obs_source_t source; + effect_t whatever; +}; + +static const char *filter_getname(const char *locale) { return "Test"; } -struct test_filter *test_create(const char *settings, obs_source_t source) +static void filter_destroy(struct test_filter *tf) +{ + if (tf) { + gs_entercontext(obs_graphics()); + + effect_destroy(tf->whatever); + bfree(tf); + + gs_leavecontext(); + } +} + +static struct test_filter *filter_create(obs_data_t settings, + obs_source_t source) { struct test_filter *tf = bzalloc(sizeof(struct test_filter)); char *effect_file; @@ -18,42 +36,27 @@ struct test_filter *test_create(const char *settings, obs_source_t source) tf->whatever = gs_create_effect_from_file(effect_file, NULL); bfree(effect_file); if (!tf->whatever) { - test_destroy(tf); + filter_destroy(tf); return NULL; } - tf->texrender = texrender_create(GS_RGBA, GS_ZS_NONE); - gs_leavecontext(); return tf; } -void test_destroy(struct test_filter *tf) +static void filter_render(struct test_filter *tf, effect_t effect) { - if (tf) { - gs_entercontext(obs_graphics()); - - effect_destroy(tf->whatever); - texrender_destroy(tf->texrender); - bfree(tf); - - gs_leavecontext(); - } + obs_source_process_filter(tf->source, tf->whatever, 0, 0, GS_RGBA, + ALLOW_DIRECT_RENDERING); } -uint32_t test_get_output_flags(struct test_filter *tf) -{ - return SOURCE_VIDEO; -} - -void test_video_tick(struct test_filter *tf, float seconds) -{ - texrender_reset(tf->texrender); -} - -void test_video_render(struct test_filter *tf) -{ - obs_source_process_filter(tf->source, tf->texrender, tf->whatever, - 0, 0, ALLOW_DIRECT_RENDERING); -} +struct obs_source_info test_filter = { + .id = "test_filter", + .type = OBS_SOURCE_TYPE_FILTER, + .output_flags = OBS_SOURCE_VIDEO, + .getname = filter_getname, + .create = filter_create, + .destroy = filter_destroy, + .video_render = filter_render +}; diff --git a/test/test-input/test-filter.h b/test/test-input/test-filter.h deleted file mode 100644 index 91b8e8a44..000000000 --- a/test/test-input/test-filter.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct test_filter { - obs_source_t source; - effect_t whatever; - texrender_t texrender; -}; - -EXPORT const char *test_getname(const char *locale); - -EXPORT struct test_filter *test_create(const char *settings, obs_source_t source); -EXPORT void test_destroy(struct test_filter *rt); -EXPORT uint32_t test_get_output_flags(struct test_filter *rt); - -EXPORT void test_video_tick(struct test_filter *rt, float seconds); -EXPORT void test_video_render(struct test_filter *rt); - -#ifdef __cplusplus -} -#endif diff --git a/test/test-input/test-input-exports.h b/test/test-input/test-input-exports.h deleted file mode 100644 index d625afd2d..000000000 --- a/test/test-input/test-input-exports.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -EXPORT uint32_t module_version(uint32_t in_version); -EXPORT bool enum_inputs(size_t idx, const char **name); -EXPORT bool enum_filters(size_t idx, const char **name); - -#ifdef __cplusplus -} -#endif diff --git a/test/test-input/test-input.c b/test/test-input/test-input.c index 30920c2ac..fe09f7697 100644 --- a/test/test-input/test-input.c +++ b/test/test-input/test-input.c @@ -1,35 +1,24 @@ -#include -#include "test-input-exports.h" +#include + +OBS_DECLARE_MODULE() + +extern struct obs_source_info test_random; +extern struct obs_source_info test_sinewave; +extern struct obs_source_info test_filter; -const char *inputs[] = { #ifdef __APPLE__ - "osx_desktop_test", +extern struct obs_source_info osx_desktop; #endif - "random", - "sinewave" -}; -const char *filters[] = {"test"}; - -uint32_t module_version(uint32_t in_version) +bool obs_module_load(uint32_t libobs_version) { - return LIBOBS_API_VER; -} + obs_register_source(&test_random); + obs_register_source(&test_sinewave); + obs_register_source(&test_filter); -bool enum_inputs(size_t idx, const char **name) -{ - if (idx >= (sizeof(inputs)/sizeof(const char*))) - return false; +#ifdef __APPLE__ + obs_register_source(&osx_desktop); +#endif - *name = inputs[idx]; - return true; -} - -bool enum_filters(size_t idx, const char **name) -{ - if (idx >= (sizeof(filters)/sizeof(const char*))) - return false; - - *name = filters[idx]; return true; } diff --git a/test/test-input/test-random.c b/test/test-input/test-random.c index 3fe04288e..f98e2fbed 100644 --- a/test/test-input/test-random.c +++ b/test/test-input/test-random.c @@ -1,12 +1,29 @@ #include -#include "test-random.h" +#include -const char *random_getname(const char *locale) +struct random_tex { + texture_t texture; +}; + +static const char *random_getname(const char *locale) { return "20x20 Random Pixel Texture Source (Test)"; } -struct random_tex *random_create(const char *settings, obs_source_t source) +static void random_destroy(struct random_tex *rt) +{ + if (rt) { + gs_entercontext(obs_graphics()); + + texture_destroy(rt->texture); + bfree(rt); + + gs_leavecontext(); + } +} + +static struct random_tex *random_create(obs_data_t settings, + obs_source_t source) { struct random_tex *rt = bzalloc(sizeof(struct random_tex)); uint32_t *pixels = bmalloc(20*20*4); @@ -39,38 +56,31 @@ struct random_tex *random_create(const char *settings, obs_source_t source) return rt; } -void random_destroy(struct random_tex *rt) +static void random_video_render(struct random_tex *rt, effect_t effect) { - if (rt) { - gs_entercontext(obs_graphics()); - - texture_destroy(rt->texture); - bfree(rt); - - gs_leavecontext(); - } -} - -uint32_t random_get_output_flags(struct random_tex *rt) -{ - return SOURCE_VIDEO | SOURCE_DEFAULT_EFFECT; -} - -void random_video_render(struct random_tex *rt, obs_source_t filter_target) -{ - effect_t effect = gs_geteffect(); - eparam_t diffuse = effect_getparambyname(effect, "diffuse"); - - effect_settexture(effect, diffuse, rt->texture); + eparam_t image = effect_getparambyname(effect, "image"); + effect_settexture(effect, image, rt->texture); gs_draw_sprite(rt->texture, 0, 0, 0); } -uint32_t random_getwidth(struct random_tex *rt) +static uint32_t random_getwidth(struct random_tex *rt) { return texture_getwidth(rt->texture); } -uint32_t random_getheight(struct random_tex *rt) +static uint32_t random_getheight(struct random_tex *rt) { return texture_getheight(rt->texture); } + +struct obs_source_info test_random = { + .id = "random", + .type = OBS_SOURCE_TYPE_INPUT, + .output_flags = OBS_SOURCE_VIDEO, + .getname = random_getname, + .create = random_create, + .destroy = random_destroy, + .video_render = random_video_render, + .getwidth = random_getwidth, + .getheight = random_getheight +}; diff --git a/test/test-input/test-random.h b/test/test-input/test-random.h deleted file mode 100644 index 2c8d96a7b..000000000 --- a/test/test-input/test-random.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct random_tex { - texture_t texture; -}; - -EXPORT const char *random_getname(const char *locale); - -EXPORT struct random_tex *random_create(const char *settings, - obs_source_t source); -EXPORT void random_destroy(struct random_tex *rt); -EXPORT uint32_t random_get_output_flags(struct random_tex *rt); - -EXPORT void random_video_render(struct random_tex *rt, - obs_source_t filter_target); - -EXPORT uint32_t random_getwidth(struct random_tex *rt); -EXPORT uint32_t random_getheight(struct random_tex *rt); - -#ifdef __cplusplus -} -#endif diff --git a/test/test-input/test-sinewave.c b/test/test-input/test-sinewave.c index 3d9b10e28..9d6bf6138 100644 --- a/test/test-input/test-sinewave.c +++ b/test/test-input/test-sinewave.c @@ -1,8 +1,18 @@ #include -#include "test-sinewave.h" +#include +#include +#include +#include + +struct sinewave_data { + bool initialized_thread; + pthread_t thread; + event_t event; + obs_source_t source; +}; /* middle C */ -const double rate = 261.63/48000.0; +static const double rate = 261.63/48000.0; #define M_PI 3.1415926535897932384626433832795 #define M_PI_X2 M_PI*2 @@ -45,12 +55,27 @@ static void *sinewave_thread(void *pdata) /* ------------------------------------------------------------------------- */ -const char *sinewave_getname(const char *locale) +static const char *sinewave_getname(const char *locale) { return "Sinewave Sound Source (Test)"; } -struct sinewave_data *sinewave_create(const char *settings, obs_source_t source) +static void sinewave_destroy(struct sinewave_data *swd) +{ + if (swd) { + if (swd->initialized_thread) { + void *ret; + event_signal(&swd->event); + pthread_join(swd->thread, &ret); + } + + event_destroy(&swd->event); + bfree(swd); + } +} + +static struct sinewave_data *sinewave_create(obs_data_t settings, + obs_source_t source) { struct sinewave_data *swd = bzalloc(sizeof(struct sinewave_data)); swd->source = source; @@ -68,21 +93,11 @@ fail: return NULL; } -void sinewave_destroy(struct sinewave_data *swd) -{ - if (swd) { - if (swd->initialized_thread) { - void *ret; - event_signal(&swd->event); - pthread_join(swd->thread, &ret); - } - - event_destroy(&swd->event); - bfree(swd); - } -} - -uint32_t sinewave_get_output_flags(struct sinewave_data *swd) -{ - return SOURCE_AUDIO; -} +struct obs_source_info test_sinewave = { + .id = "test_sinewave", + .type = OBS_SOURCE_TYPE_INPUT, + .output_flags = OBS_SOURCE_AUDIO, + .getname = sinewave_getname, + .create = sinewave_create, + .destroy = sinewave_destroy, +}; diff --git a/test/test-input/test-sinewave.h b/test/test-input/test-sinewave.h deleted file mode 100644 index 5984a1071..000000000 --- a/test/test-input/test-sinewave.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct sinewave_data { - bool initialized_thread; - pthread_t thread; - event_t event; - obs_source_t source; -}; - -EXPORT const char *sinewave_getname(const char *locale); - -EXPORT struct sinewave_data *sinewave_create(const char *settings, - obs_source_t source); -EXPORT void sinewave_destroy(struct sinewave_data *swd); -EXPORT uint32_t sinewave_get_output_flags(struct sinewave_data *swd); - -#ifdef __cplusplus -} -#endif diff --git a/test/win/test.cpp b/test/win/test.cpp index b5c43aee2..c6fb0c4cc 100644 --- a/test/win/test.cpp +++ b/test/win/test.cpp @@ -110,7 +110,8 @@ static HWND CreateTestWindow(HINSTANCE instance) if (!RegisterClass(&wc)) return 0; - return CreateWindow(TEXT("bla"), TEXT("bla"), WS_OVERLAPPEDWINDOW|WS_VISIBLE, + return CreateWindow(TEXT("bla"), TEXT("bla"), + WS_OVERLAPPEDWINDOW|WS_VISIBLE, 1920/2 - cx/2, 1080/2 - cy/2, cx, cy, NULL, NULL, instance, NULL); } @@ -139,14 +140,14 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, /* ------------------------------------------------------ */ /* create source */ - SourceContext source = obs_source_create(SOURCE_INPUT, + SourceContext source = obs_source_create(OBS_SOURCE_TYPE_INPUT, "random", "some randon source", NULL); if (!source) throw "Couldn't create random test source"; /* ------------------------------------------------------ */ /* create filter */ - SourceContext filter = obs_source_create(SOURCE_FILTER, + SourceContext filter = obs_source_create(OBS_SOURCE_TYPE_FILTER, "test", "a nice little green filter", NULL); if (!filter) throw "Couldn't create test filter"; diff --git a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj index 86513b4ee..b29fc4c6a 100644 --- a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj +++ b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj @@ -174,9 +174,6 @@ - - - diff --git a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters index 9f5287c60..e51f288a7 100644 --- a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters +++ b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters @@ -22,9 +22,4 @@ Source Files - - - Header Files - - \ No newline at end of file diff --git a/vs/2013/test-input/test-input.vcxproj b/vs/2013/test-input/test-input.vcxproj index 8cb322f51..6dd8b0142 100644 --- a/vs/2013/test-input/test-input.vcxproj +++ b/vs/2013/test-input/test-input.vcxproj @@ -18,12 +18,6 @@ x64 - - - - - - diff --git a/vs/2013/test-input/test-input.vcxproj.filters b/vs/2013/test-input/test-input.vcxproj.filters index cb0e6f51e..a12ca1563 100644 --- a/vs/2013/test-input/test-input.vcxproj.filters +++ b/vs/2013/test-input/test-input.vcxproj.filters @@ -14,20 +14,6 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - Source Files