From 409b011a8ed6b12e067a115570fdb0179a87c053 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Wed, 20 Nov 2013 15:00:16 -0700 Subject: [PATCH] cleaned up main internal data structure design, changed to reference counting for sources to ensure safe destruction of source objects from all parts of the system, added some service-related stuff for testing --- libobs-d3d11/d3d11-subsystem.cpp | 6 +- libobs-opengl/gl-cocoa.m | 6 +- libobs-opengl/gl-windows.c | 2 +- libobs/graphics/graphics.h | 9 +- libobs/obs-data.h | 86 +- libobs/obs-display.c | 28 +- libobs/obs-scene.c | 22 +- libobs/obs-service.h | 7 +- libobs/obs-source.c | 103 +- libobs/obs-source.h | 11 +- libobs/obs-video.c | 72 +- libobs/obs.c | 383 ++-- libobs/obs.h | 75 +- plugins/obs-outputs/obs-outputs.c | 2 +- plugins/obs-outputs/obs-outputs.fbp | 2590 +++++++++++++++++++++++++++ plugins/obs-outputs/obs-stream.h | 2 +- test/osx/test.mm | 39 +- test/win/test.cpp | 39 +- 18 files changed, 3155 insertions(+), 327 deletions(-) create mode 100644 plugins/obs-outputs/obs-outputs.fbp diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index a6aa383d6..93b612515 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -32,7 +32,7 @@ static inline void make_swap_desc(DXGI_SWAP_CHAIN_DESC &desc, desc.BufferDesc.Width = data->cx; desc.BufferDesc.Height = data->cy; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.OutputWindow = (HWND)data->hwnd; + desc.OutputWindow = (HWND)data->window.hwnd; desc.SampleDesc.Count = 1; desc.Windowed = true; } @@ -109,7 +109,7 @@ void gs_swap_chain::Init(gs_init_data *data) gs_swap_chain::gs_swap_chain(gs_device *device, gs_init_data *data) : device (device), numBuffers (data->num_backbuffers), - hwnd ((HWND)data->hwnd) + hwnd ((HWND)data->window.hwnd) { HRESULT hr; DXGI_SWAP_CHAIN_DESC swapDesc; @@ -182,7 +182,7 @@ void gs_device::InitDevice(gs_init_data *data, IDXGIAdapter *adapter) (uint32_t)levelUsed); defaultSwap.device = this; - defaultSwap.hwnd = (HWND)data->hwnd; + defaultSwap.hwnd = (HWND)data->window.hwnd; defaultSwap.numBuffers = data->num_backbuffers; defaultSwap.Init(data); } diff --git a/libobs-opengl/gl-cocoa.m b/libobs-opengl/gl-cocoa.m index 3605a01e0..911972700 100644 --- a/libobs-opengl/gl-cocoa.m +++ b/libobs-opengl/gl-cocoa.m @@ -92,7 +92,7 @@ static NSOpenGLContext *gl_context_create(struct gs_init_data *info) return NULL; } - [context setView:info->view]; + [context setView:info->window.view]; return context; } @@ -200,13 +200,13 @@ struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info) if(!info) return NULL; - if(!info->view) + if(!info->window.view) return NULL; struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo)); memset(wi, 0, sizeof(struct gl_windowinfo)); - wi->view = info->view; + wi->view = info->window.view; return wi; } diff --git a/libobs-opengl/gl-windows.c b/libobs-opengl/gl-windows.c index 44bc2db46..3688ee3e7 100644 --- a/libobs-opengl/gl-windows.c +++ b/libobs-opengl/gl-windows.c @@ -350,7 +350,7 @@ static struct gl_windowinfo *gl_windowinfo_bare(struct gs_init_data *info) struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo)); memset(wi, 0, sizeof(struct gl_windowinfo)); - wi->hwnd = info->hwnd; + wi->hwnd = info->window.hwnd; wi->hdc = GetDC(wi->hwnd); if (!wi->hdc) { blog(LOG_ERROR, "Unable to get device context from window"); diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index a754c8304..94e8f6bc8 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -405,18 +405,23 @@ EXPORT texture_t texrender_gettexture(texrender_t texrender); /* ---------------- */ /* global functions */ -#define GS_SUCCESS 0 +#define GS_SUCCESS 0 #define GS_ERROR_MODULENOTFOUND -1 #define GS_ERROR_FAIL -2 -struct gs_init_data { +struct gs_window { #if defined(_WIN32) void *hwnd; #elif defined(__APPLE__) __unsafe_unretained id view; #elif defined(__posix__) + int bla; /* TODO */ #endif +}; + +struct gs_init_data { + struct gs_window window; uint32_t cx, cy; uint32_t num_backbuffers; enum gs_color_format format; diff --git a/libobs/obs-data.h b/libobs/obs-data.h index 9b0660ba7..2163c52e3 100644 --- a/libobs/obs-data.h +++ b/libobs/obs-data.h @@ -33,52 +33,64 @@ /*#include "obs-service.h"*/ #define NUM_TEXTURES 2 +#define MAX_CHANNELS 32 struct obs_display { - swapchain_t swap; /* can be NULL if just sound */ - obs_source_t source; + swapchain_t swap; /* can be NULL if just sound */ + obs_source_t channels[MAX_CHANNELS]; + /* TODO: sound output target */ }; -struct obs_data { - 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 service_info) service_types;*/ +struct obs_video { + graphics_t graphics; + stagesurf_t copy_surfaces[NUM_TEXTURES]; + effect_t default_effect; + bool textures_copied[NUM_TEXTURES]; + bool copy_mapped; + int cur_texture; - DARRAY(struct obs_display*) displays; - DARRAY(struct obs_source*) sources; + video_t video; + pthread_t video_thread; + bool thread_initialized; - /* graphics */ - graphics_t graphics; - stagesurf_t copy_surfaces[NUM_TEXTURES]; - effect_t default_effect; - bool textures_copied[NUM_TEXTURES]; - bool copy_mapped; - int cur_texture; - - /* TODO: sound output stuff */ - - /* media */ - media_t media; - video_t video; - audio_t audio; - - uint32_t output_width; - uint32_t output_height; - - /* threading */ - pthread_t video_thread; - bool thread_initialized; - pthread_mutex_t source_list_mutex; - pthread_mutex_t display_list_mutex; - - obs_source_t primary_source; + uint32_t output_width; + uint32_t output_height; }; -extern struct obs_data *obs; +struct obs_audio { + /* TODO: audio subsystem */ + audio_t audio; +}; + +struct obs_data { + DARRAY(struct obs_display*) displays; + DARRAY(struct obs_source*) sources; + + obs_source_t channels[MAX_CHANNELS]; + pthread_mutex_t sources_mutex; + pthread_mutex_t displays_mutex; +}; + +struct obs_subsystem { + 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 service_info) service_types; + + media_t media; + + /* segmented into multiple sub-structures to keep things a bit more + * clean and organized */ + struct obs_video video; + struct obs_audio audio; + struct obs_data data; +}; + +extern struct obs_subsystem *obs; extern void *obs_video_thread(void *param); diff --git a/libobs/obs-display.c b/libobs/obs-display.c index ee56ac8e3..7867c98d9 100644 --- a/libobs/obs-display.c +++ b/libobs/obs-display.c @@ -37,17 +37,37 @@ obs_display_t obs_display_create(struct gs_init_data *graphics_data) void obs_display_destroy(obs_display_t display) { if (display) { + size_t i; + + pthread_mutex_lock(&obs->data.displays_mutex); + da_erase_item(obs->data.displays, &display); + pthread_mutex_unlock(&obs->data.displays_mutex); + + for (i = 0; i < MAX_CHANNELS; i++) + obs_source_release(display->channels[i]); + swapchain_destroy(display->swap); bfree(display); } } -obs_source_t obs_display_getsource(obs_display_t display) +obs_source_t obs_display_getsource(obs_display_t display, uint32_t channel) { - return display->source; + assert(channel < MAX_CHANNELS); + return display->channels[channel]; } -void obs_display_setsource(obs_display_t display, obs_source_t source) +void obs_display_setsource(obs_display_t display, uint32_t channel, + obs_source_t source) { - display->source = source; + struct obs_source *prev_source; + assert(channel < MAX_CHANNELS); + + prev_source = display->channels[channel]; + display->channels[channel] = source; + + if (source) + obs_source_addref(source); + if (prev_source) + obs_source_release(prev_source); } diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index db75d572b..4b0fd620f 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -38,8 +38,12 @@ static void scene_destroy(void *data) struct obs_scene *scene = data; size_t i; - for (i = 0; i < scene->items.num; i++) - bfree(scene->items.array[i]); + for (i = 0; i < scene->items.num; i++) { + struct obs_scene_item *item = scene->items.array[i]; + if (item->source) + obs_source_release(item->source); + bfree(item); + } da_free(scene->items); bfree(scene); @@ -58,6 +62,12 @@ static void scene_video_render(void *data) for (i = scene->items.num; i > 0; i--) { struct obs_scene_item *item = scene->items.array[i-1]; + if (obs_source_removed(item->source)) { + obs_source_release(item->source); + da_erase(scene->items, i--); + continue; + } + gs_matrix_push(); gs_matrix_translate3f(item->origin.x, item->origin.y, 0.0f); gs_matrix_scale3f(item->scale.x, item->scale.y, 1.0f); @@ -136,7 +146,7 @@ obs_scene_t obs_scene_create(void) void obs_scene_destroy(obs_scene_t scene) { if (scene) - obs_source_destroy(scene->source); + obs_source_release(scene->source); } obs_source_t obs_scene_getsource(obs_scene_t scene) @@ -153,6 +163,9 @@ obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source) item->parent = scene; vec2_set(&item->scale, 1.0f, 1.0f); + if (source) + obs_source_addref(source); + da_push_back(scene->items, &item); return item; } @@ -160,6 +173,9 @@ obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source) void obs_sceneitem_destroy(obs_sceneitem_t item) { if (item) { + if (item->source) + obs_source_release(item->source); + da_erase_item(item->parent->items, item); bfree(item); } diff --git a/libobs/obs-service.h b/libobs/obs-service.h index d6eb584dc..5347e1ade 100644 --- a/libobs/obs-service.h +++ b/libobs/obs-service.h @@ -20,10 +20,15 @@ struct service_data; struct service_info { + const char *(*getname)(const char *locale); + void *(*create)(const char *settings, struct service_data *service); void (*destroy)(void *data); void (*config)(void *data, const char *settings); - + + /* optional */ + const char *(*getdata)(const char *attribute); + /* get stream url/key */ /* get (viewers/etc) */ /* send (current game/title/activate commercial/etc) */ diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 3931c37e8..4a6c92074 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -21,6 +21,8 @@ #include "obs.h" #include "obs-data.h" +static void obs_source_destroy(obs_source_t source); + bool get_source_info(void *module, const char *module_name, const char *source_name, struct source_info *info) { @@ -88,6 +90,7 @@ bool obs_source_init(struct obs_source *source, const char *settings, { uint32_t flags = info->get_output_flags(source->data); + source->refs = 1; pthread_mutex_init_value(&source->filter_mutex); pthread_mutex_init_value(&source->video_mutex); pthread_mutex_init_value(&source->audio_mutex); @@ -102,7 +105,7 @@ bool obs_source_init(struct obs_source *source, const char *settings, return false; if (flags & SOURCE_AUDIO) { - source->audio_line = audio_output_createline(obs->audio); + source->audio_line = audio_output_createline(obs->audio.audio); if (!source->audio_line) { blog(LOG_ERROR, "Failed to create audio line for " "source"); @@ -110,11 +113,6 @@ bool obs_source_init(struct obs_source *source, const char *settings, } } - source->valid = true; - pthread_mutex_lock(&obs->source_list_mutex); - da_push_back(obs->sources, &source); - pthread_mutex_unlock(&obs->source_list_mutex); - return true; } @@ -158,47 +156,64 @@ fail: return NULL; } -void obs_source_destroy(obs_source_t source) +static void obs_source_destroy(obs_source_t source) { - if (source) { - size_t i; - if (source->filter_parent) - obs_source_filter_remove(source->filter_parent, source); + size_t i; - for (i = 0; i < source->filters.num; i++) - obs_source_destroy(source->filters.array[i]); + if (source->filter_parent) + obs_source_filter_remove(source->filter_parent, source); - if (source->valid) { - pthread_mutex_lock(&obs->source_list_mutex); - da_erase_item(obs->sources, &source); - pthread_mutex_unlock(&obs->source_list_mutex); - } + for (i = 0; i < source->filters.num; i++) + obs_source_release(source->filters.array[i]); - for (i = 0; i < source->audio_wait_buffer.num; i++) - audiobuf_free(source->audio_wait_buffer.array+i); - for (i = 0; i < source->video_frames.num; i++) - source_frame_destroy(source->video_frames.array[i]); + for (i = 0; i < source->audio_wait_buffer.num; i++) + audiobuf_free(source->audio_wait_buffer.array+i); + for (i = 0; i < source->video_frames.num; i++) + source_frame_destroy(source->video_frames.array[i]); - gs_entercontext(obs->graphics); - texture_destroy(source->output_texture); - gs_leavecontext(); + gs_entercontext(obs->video.graphics); + texture_destroy(source->output_texture); + gs_leavecontext(); - if (source->data) - source->callbacks.destroy(source->data); + if (source->data) + source->callbacks.destroy(source->data); - bfree(source->audio_data.data); - audio_line_destroy(source->audio_line); - audio_resampler_destroy(source->resampler); + bfree(source->audio_data.data); + audio_line_destroy(source->audio_line); + audio_resampler_destroy(source->resampler); - da_free(source->video_frames); - da_free(source->audio_wait_buffer); - da_free(source->filters); - pthread_mutex_destroy(&source->filter_mutex); - pthread_mutex_destroy(&source->audio_mutex); - pthread_mutex_destroy(&source->video_mutex); - dstr_free(&source->settings); - bfree(source); - } + da_free(source->video_frames); + da_free(source->audio_wait_buffer); + da_free(source->filters); + pthread_mutex_destroy(&source->filter_mutex); + pthread_mutex_destroy(&source->audio_mutex); + pthread_mutex_destroy(&source->video_mutex); + dstr_free(&source->settings); + bfree(source); +} + +void obs_source_addref(obs_source_t source) +{ + assert(source != NULL); + if (!source) + return; + + ++source->refs; +} + +void obs_source_release(obs_source_t source) +{ + assert(source != NULL); + if (!source) + return; + + if (--source->refs == 0) + obs_source_destroy(source); +} + +bool obs_source_removed(obs_source_t source) +{ + return source->removed; } uint32_t obs_source_get_output_flags(obs_source_t source) @@ -394,7 +409,7 @@ static bool upload_frame(texture_t tex, const struct source_frame *frame) static void obs_source_draw_texture(texture_t tex, struct source_frame *frame) { - effect_t effect = obs->default_effect; + effect_t effect = obs->video.default_effect; bool yuv = is_yuv(frame->format); const char *type = yuv ? "DrawYUVToRGB" : "DrawRGB"; technique_t tech; @@ -655,9 +670,11 @@ static inline struct filtered_audio *filter_async_audio(obs_source_t source, static inline void reset_resampler(obs_source_t source, const struct source_audio *audio) { - const struct audio_info *obs_info = audio_output_getinfo(obs->audio); + const struct audio_info *obs_info; struct resample_info output_info; + obs_info = audio_output_getinfo(obs->audio.audio); + output_info.format = obs_info->format; output_info.samples_per_sec = obs_info->samples_per_sec; output_info.speakers = obs_info->speakers; @@ -685,7 +702,7 @@ static inline void reset_resampler(obs_source_t source, static inline void copy_audio_data(obs_source_t source, const void *data, uint32_t frames, uint64_t timestamp) { - size_t blocksize = audio_output_blocksize(obs->audio); + size_t blocksize = audio_output_blocksize(obs->audio.audio); size_t size = (size_t)frames * blocksize; /* ensure audio storage capacity */ @@ -731,7 +748,7 @@ void obs_source_output_audio(obs_source_t source, const struct source_audio *audio) { uint32_t flags = obs_source_get_output_flags(source); - size_t blocksize = audio_output_blocksize(obs->audio); + size_t blocksize = audio_output_blocksize(obs->audio.audio); struct filtered_audio *output; process_audio(source, audio); diff --git a/libobs/obs-source.h b/libobs/obs-source.h index 899f8bb61..20d1248f8 100644 --- a/libobs/obs-source.h +++ b/libobs/obs-source.h @@ -211,10 +211,17 @@ static inline void audiobuf_free(struct audiobuf *buf) } struct obs_source { - void *data; /* source-specific data */ + volatile int refs; + + /* source-specific data */ + void *data; struct source_info callbacks; struct dstr settings; - bool valid; + + /* 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; /* async video and audio */ bool timing_set; diff --git a/libobs/obs-video.c b/libobs/obs-video.c index 3842bec80..4ea29f723 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -26,12 +26,12 @@ static void tick_sources(uint64_t cur_time, uint64_t *last_time) float seconds; if (!last_time) - *last_time = cur_time - video_getframetime(obs->video); + *last_time = cur_time - video_getframetime(obs->video.video); delta_time = cur_time - *last_time; seconds = (float)((double)delta_time / 1000000000.0); - for (i = 0; i < obs->sources.num; i++) - obs_source_video_tick(obs->sources.array[i], seconds); + for (i = 0; i < obs->data.sources.num; i++) + obs_source_video_tick(obs->data.sources.array[i], seconds); *last_time = cur_time; } @@ -40,6 +40,7 @@ static inline void render_display(struct obs_display *display) { struct vec4 clear_color; uint32_t width, height; + size_t i; gs_load_swapchain(display ? display->swap : NULL); @@ -51,14 +52,27 @@ static inline void render_display(struct obs_display *display) &clear_color, 1.0f, 0); gs_enable_depthtest(false); - gs_enable_blending(false); + /* gs_enable_blending(false); */ gs_setcullmode(GS_NEITHER); gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f); gs_setviewport(0, 0, width, height); - if (obs->primary_source) - obs_source_video_render(obs->primary_source); + for (i = 0; i < MAX_CHANNELS; i++) { + struct obs_source **p_source; + + p_source = (display) ? display->channels+i : + obs->data.channels+i; + + if (*p_source) { + if ((*p_source)->removed) { + obs_source_release(*p_source); + *p_source = NULL; + } else { + obs_source_video_render(*p_source); + } + } + } gs_endscene(); gs_present(); @@ -68,56 +82,58 @@ static inline void render_displays(void) { size_t i; - pthread_mutex_lock(&obs->display_list_mutex); + /* render extra displays/swaps */ + pthread_mutex_lock(&obs->data.displays_mutex); - for (i = 0; i < obs->displays.num; i++) { - struct obs_display *display = obs->displays.array[i]; + for (i = 0; i < obs->data.displays.num; i++) + render_display(obs->data.displays.array[i]); - render_display(display); - } - - pthread_mutex_unlock(&obs->display_list_mutex); + pthread_mutex_unlock(&obs->data.displays_mutex); + /* render main display */ render_display(NULL); } static bool swap_frame(uint64_t timestamp) { - stagesurf_t last_surface = obs->copy_surfaces[obs->cur_texture]; + struct obs_video *video = &obs->video; + stagesurf_t last_surface = video->copy_surfaces[video->cur_texture]; stagesurf_t surface; struct video_frame frame; - if (obs->copy_mapped) { + /* the last frame stays mapped until rendering starts with the next */ + if (video->copy_mapped) { stagesurface_unmap(last_surface); - obs->copy_mapped = false; + video->copy_mapped = false; } - obs->textures_copied[obs->cur_texture] = true; - //gs_stage_texture(last_surface, NULL); + video->textures_copied[video->cur_texture] = true; + /* TODO: texture staging */ + //gs_stage_texture(last_surface, ); - if (++obs->cur_texture == NUM_TEXTURES) - obs->cur_texture = 0; + if (++video->cur_texture == NUM_TEXTURES) + video->cur_texture = 0; - if (obs->textures_copied[obs->cur_texture]) { - surface = obs->copy_surfaces[obs->cur_texture]; - obs->copy_mapped = stagesurface_map(surface, &frame.data, + if (video->textures_copied[video->cur_texture]) { + surface = video->copy_surfaces[video->cur_texture]; + video->copy_mapped = stagesurface_map(surface, &frame.data, &frame.row_size); - if (obs->copy_mapped) { + if (video->copy_mapped) { frame.timestamp = timestamp; - video_output_frame(obs->video, &frame); + video_output_frame(video->video, &frame); } } - return obs->copy_mapped; + return video->copy_mapped; } void *obs_video_thread(void *param) { uint64_t last_time = 0; - while (video_output_wait(obs->video)) { - uint64_t cur_time = video_gettime(obs->video); + while (video_output_wait(obs->video.video)) { + uint64_t cur_time = video_gettime(obs->video.video); gs_entercontext(obs_graphics()); diff --git a/libobs/obs.c b/libobs/obs.c index 2e32e04f1..bb55d6cb2 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -19,40 +19,71 @@ #include "obs-data.h" #include "obs-module.h" -struct obs_data *obs = NULL; +struct obs_subsystem *obs = NULL; extern char *find_libobs_data_file(const char *file); -static bool obs_init_graphics(const char *graphics_module, - struct gs_init_data *graphics_data, struct video_info *vi) +static inline void make_gs_init_data(struct gs_init_data *gid, + struct obs_video_info *ovi) { - int errorcode; + memcpy(&gid->window, &ovi->window, sizeof(struct gs_window)); + gid->cx = ovi->base_width; + gid->cy = ovi->base_height; + gid->num_backbuffers = 2; + gid->format = GS_RGBA; + gid->zsformat = GS_ZS_NONE; + gid->adapter = ovi->adapter; +} + +static inline void make_video_info(struct video_info *vi, + struct obs_video_info *ovi) +{ + vi->name = "video"; + vi->type = ovi->output_format; + vi->fps_num = ovi->fps_num; + vi->fps_den = ovi->fps_den; + vi->width = ovi->output_width; + vi->height = ovi->output_height; +} + +static bool obs_init_graphics(struct obs_video_info *ovi) +{ + struct obs_video *video = &obs->video; + struct gs_init_data graphics_data; bool success = true; + int errorcode; size_t i; - errorcode = gs_create(&obs->graphics, graphics_module, graphics_data); + make_gs_init_data(&graphics_data, ovi); + video->output_width = ovi->output_width; + video->output_height = ovi->output_height; + + errorcode = gs_create(&video->graphics, ovi->graphics_module, + &graphics_data); if (errorcode != GS_SUCCESS) { if (errorcode == GS_ERROR_MODULENOTFOUND) blog(LOG_ERROR, "Could not find graphics module '%s'", - graphics_module); + ovi->graphics_module); return false; } - gs_entercontext(obs->graphics); + gs_entercontext(video->graphics); for (i = 0; i < NUM_TEXTURES; i++) { - obs->copy_surfaces[i] = gs_create_stagesurface(vi->width, - vi->height, graphics_data->format); - if (!obs->copy_surfaces[i]) + video->copy_surfaces[i] = gs_create_stagesurface( + ovi->output_width, ovi->output_height, + graphics_data.format); + + if (!video->copy_surfaces[i]) success = false; } if (success) { char *filename = find_libobs_data_file("default.effect"); - obs->default_effect = gs_create_effect_from_file( filename, + video->default_effect = gs_create_effect_from_file(filename, NULL); bfree(filename); - if (!obs->default_effect) + if (!video->default_effect) success = false; } @@ -60,114 +91,179 @@ static bool obs_init_graphics(const char *graphics_module, return success; } -static bool obs_init_media(struct video_info *vi, struct audio_info *ai) +static bool obs_init_video(struct obs_video_info *ovi) { + struct obs_video *video = &obs->video; + struct video_info vi; + int errorcode; + + memset(video, 0, sizeof(struct obs_video)); + + if (!obs_init_graphics(ovi)) + return false; + + make_video_info(&vi, ovi); + errorcode = video_output_open(&video->video, obs->media, &vi); + + if (errorcode != VIDEO_OUTPUT_SUCCESS) { + if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) + blog(LOG_ERROR, "Invalid video parameters specified"); + else + blog(LOG_ERROR, "Could not open video output"); + + return false; + } + + errorcode = pthread_create(&video->video_thread, NULL, + obs_video_thread, obs); + if (errorcode != 0) + return false; + + video->thread_initialized = true; + return true; +} + +static void obs_free_video(void) +{ + struct obs_video *video = &obs->video; + size_t i; + + if (video->video) { + void *thread_retval; + + video_output_stop(video->video); + if (video->thread_initialized) + pthread_join(video->video_thread, &thread_retval); + + video_output_close(video->video); + } + + if (video->graphics) { + int cur_texture = video->cur_texture; + gs_entercontext(video->graphics); + + if (video->copy_mapped) + stagesurface_unmap(video->copy_surfaces[cur_texture]); + + for (i = 0; i < NUM_TEXTURES; i++) + stagesurface_destroy(video->copy_surfaces[i]); + + effect_destroy(video->default_effect); + + gs_leavecontext(); + + gs_destroy(video->graphics); + } + + memset(video, 0, sizeof(struct obs_video)); +} + +static bool obs_init_audio(struct audio_info *ai) +{ + struct obs_audio *audio = &obs->audio; + int errorcode; + + /* TODO: sound subsystem */ + + errorcode = audio_output_open(&audio->audio, obs->media, ai); + if (errorcode == AUDIO_OUTPUT_SUCCESS) + return true; + else if (errorcode= AUDIO_OUTPUT_INVALIDPARAM) + blog(LOG_ERROR, "Invalid audio parameters specified"); + else + blog(LOG_ERROR, "Could not open audio output"); + + return false; +} + +static void obs_free_audio(void) +{ + struct obs_audio *audio = &obs->audio; + if (audio->audio) + audio_output_close(audio->audio); + + memset(audio, 0, sizeof(struct obs_audio)); +} + +static bool obs_init_data(void) +{ + struct obs_data *data = &obs->data; + + pthread_mutex_init_value(&obs->data.displays_mutex); + + if (pthread_mutex_init(&data->sources_mutex, NULL) != 0) + return false; + if (pthread_mutex_init(&data->displays_mutex, NULL) != 0) + return false; + + return true; +} + +static void obs_free_data(void) +{ + struct obs_data *data = &obs->data; + size_t i; + + for (i = 0; i < MAX_CHANNELS; i++) + obs_set_output_source(i, NULL); + + while (data->displays.num) + obs_display_destroy(data->displays.array[0]); + + pthread_mutex_lock(&obs->data.sources_mutex); + for (i = 0; i < data->sources.num; i++) + obs_source_release(data->sources.array[i]); + da_free(data->sources); + pthread_mutex_unlock(&obs->data.sources_mutex); +} + +static bool obs_init(void) +{ + obs = bmalloc(sizeof(struct obs_subsystem)); + + memset(obs, 0, sizeof(struct obs_subsystem)); + obs_init_data(); + obs->media = media_open(); if (!obs->media) return false; - if (!obs_reset_video(vi)) - return false; - if (!obs_reset_audio(ai)) - return false; - return true; } -static bool obs_init_threading(void) +bool obs_startup() { - if (pthread_mutex_init(&obs->source_list_mutex, NULL) != 0) - return false; - if (pthread_mutex_init(&obs->display_list_mutex, NULL) != 0) - return false; - if (pthread_create(&obs->video_thread, NULL, obs_video_thread, - obs) != 0) - return false; + bool success; - obs->thread_initialized = true; - return true; + if (obs) { + blog(LOG_ERROR, "Tried to call obs_startup more than once"); + return false; + } + + success = obs_init(); + if (!success) + obs_shutdown(); + + return success; } -static bool obs_init(const char *graphics_module, - struct gs_init_data *graphics_data, - struct video_info *vi, struct audio_info *ai) -{ - obs = bmalloc(sizeof(struct obs_data)); - - memset(obs, 0, sizeof(struct obs_data)); - pthread_mutex_init_value(&obs->source_list_mutex); - pthread_mutex_init_value(&obs->display_list_mutex); - - if (!obs_init_graphics(graphics_module, graphics_data, vi)) - return false; - if (!obs_init_media(vi, ai)) - return false; - if (!obs_init_threading()) - return false; - - return true; -} - -static inline void obs_free_graphics(void) -{ - size_t i; - if (!obs->graphics) - return; - - gs_entercontext(obs->graphics); - - if (obs->copy_mapped) - stagesurface_unmap(obs->copy_surfaces[obs->cur_texture]); - - for (i = 0; i < NUM_TEXTURES; i++) - stagesurface_destroy(obs->copy_surfaces[i]); - - effect_destroy(obs->default_effect); - - gs_leavecontext(); - - gs_destroy(obs->graphics); -} - -static inline void obs_free_media(void) -{ - video_output_close(obs->video); - audio_output_close(obs->audio); - media_close(obs->media); -} - -static inline void obs_free_threading(void) -{ - void *thread_ret; - video_output_stop(obs->video); - if (obs->thread_initialized) - pthread_join(obs->video_thread, &thread_ret); - pthread_mutex_destroy(&obs->source_list_mutex); - pthread_mutex_destroy(&obs->display_list_mutex); -} - -static void obs_destroy(void) +void obs_shutdown(void) { size_t i; if (!obs) return; - for (i = 0; i < obs->displays.num; i++) - obs_display_destroy(obs->displays.array[i]); - da_free(obs->input_types); da_free(obs->filter_types); da_free(obs->transition_types); da_free(obs->output_types); - /*da_free(obs->services);*/ + da_free(obs->service_types); - da_free(obs->displays); - da_free(obs->sources); - - obs_free_threading(); - obs_free_media(); - obs_free_graphics(); + obs_free_data(); + obs_free_video(); + obs_free_audio(); + media_close(obs->media); for (i = 0; i < obs->modules.num; i++) free_module(obs->modules.array+i); @@ -177,53 +273,24 @@ static void obs_destroy(void) obs = NULL; } -bool obs_startup(const char *graphics_module, - struct gs_init_data *graphics_data, - struct video_info *vi, struct audio_info *ai) +bool obs_reset_video(struct obs_video_info *ovi) { - if (!obs_init(graphics_module, graphics_data, vi, ai)) { - obs_destroy(); - return false; - } + obs_free_video(); + if (ovi) + return obs_init_video(ovi); return true; } -void obs_shutdown(void) -{ - obs_destroy(); -} - -bool obs_reset_video(struct video_info *vi) -{ - int errorcode; - - if (obs->video) { - video_output_close(obs->video); - obs->video = NULL; - } - - obs->output_width = vi->width; - obs->output_height = vi->height; - - errorcode = video_output_open(&obs->video, obs->media, vi); - if (errorcode == VIDEO_OUTPUT_SUCCESS) - return true; - else if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) - blog(LOG_ERROR, "Invalid video parameters specified"); - else - blog(LOG_ERROR, "Could not open video output"); - - return false; -} - bool obs_reset_audio(struct audio_info *ai) { - /* TODO */ + obs_free_audio(); + if(ai) + return obs_init_audio(ai); + return true; } - bool obs_enum_inputs(size_t idx, const char **name) { if (idx >= obs->input_types.num) @@ -256,10 +323,9 @@ bool obs_enum_outputs(size_t idx, const char **name) return true; } - graphics_t obs_graphics(void) { - return obs->graphics; + return obs->video.graphics; } media_t obs_media(void) @@ -267,12 +333,49 @@ media_t obs_media(void) return obs->media; } -obs_source_t obs_get_primary_source(void) +bool obs_add_source(obs_source_t source) { - return obs->primary_source; + pthread_mutex_lock(&obs->data.sources_mutex); + da_push_back(obs->data.sources, &source); + obs_source_addref(source); + pthread_mutex_unlock(&obs->data.sources_mutex); + + return true; } -void obs_set_primary_source(obs_source_t source) +void obs_delete_source(obs_source_t source) { - obs->primary_source = source; + struct obs_data *data = &obs->data; + size_t id; + + pthread_mutex_lock(&data->sources_mutex); + + id = da_find(data->sources, &source, 0); + if (id != DARRAY_INVALID) { + source->removed = true; + da_erase_item(data->sources, &source); + obs_source_release(source); + } + + pthread_mutex_unlock(&data->sources_mutex); +} + +obs_source_t obs_get_output_source(uint32_t channel) +{ + assert(channel < MAX_CHANNELS); + return obs->data.channels[channel]; +} + +void obs_set_output_source(uint32_t channel, obs_source_t source) +{ + struct obs_source *prev_source; + assert(channel < MAX_CHANNELS); + + prev_source = obs->data.channels[channel]; + obs->data.channels[channel] = source; + + if (source) + obs_source_addref(source); + if (prev_source) + obs_source_release(prev_source); } diff --git a/libobs/obs.h b/libobs/obs.h index 74510cdd7..d5c0ce653 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -46,6 +46,11 @@ enum obs_source_type { SOURCE_SCENE }; +enum obs_video_type { + OBS_VIDEO_YUV, + OBS_VIDEO_RGB +}; + /* used for changing the order of items (for example, filters in a source, * or items in a scene) */ enum order_movement { @@ -55,6 +60,19 @@ enum order_movement { ORDER_MOVE_BOTTOM }; +struct obs_video_info { + const char *graphics_module; + uint32_t fps_num; + uint32_t fps_den; + uint32_t base_width; + uint32_t base_height; + uint32_t output_width; + uint32_t output_height; + enum video_format output_format; + uint32_t adapter; + struct gs_window window; +}; + struct filtered_audio { void *data; uint32_t frames; @@ -100,12 +118,14 @@ struct obs_source; struct obs_scene; struct obs_scene_item; struct obs_output; +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_service *obs_service_t; /* ------------------------------------------------------------------------- */ /* OBS context */ @@ -113,21 +133,17 @@ typedef struct obs_output *obs_output_t; /** * Starts up and shuts down OBS * - * Using the graphics module specified, creates an OBS context and sets the - * primary video/audio output information. + * Creates the OBS context. */ -EXPORT bool obs_startup(const char *graphics_module, - struct gs_init_data *graphics_data, - struct video_info *vi, struct audio_info *ai); +EXPORT bool obs_startup(void); EXPORT void obs_shutdown(void); /** * Sets base video ouput base resolution/fps/format * - * NOTE: Cannot reset base video if currently streaming/recording. + * NOTE: Cannot set base video if currently streaming/recording. */ - -EXPORT bool obs_reset_video(struct video_info *vi); +EXPORT bool obs_reset_video(struct obs_video_info *ovi); /** * Sets base audio output format/channels/samples/etc @@ -184,18 +200,24 @@ EXPORT graphics_t obs_graphics(void); EXPORT media_t obs_media(void); /** - * Sets/gets the primary output source. + * Adds/removes a source to/from the user source list. * - * The primary source is the source that's presented. + * The user source list is the list of sources that are accessible by a user. + * Typically when a transition is active, it is not meant to be accessible by + * users, so there's no reason for a user to see such a source. */ -EXPORT void obs_set_primary_source(obs_source_t source); -EXPORT obs_source_t obs_get_primary_source(void); +EXPORT bool obs_add_source(obs_source_t source); +EXPORT void obs_delete_source(obs_source_t source); + +/** Sets/gets the primary output source for a channel. */ +EXPORT void obs_set_output_source(uint32_t channel, obs_source_t source); +EXPORT obs_source_t obs_get_output_source(uint32_t channel); /** * Returns the location of a plugin data file. * * file: Name of file to locate. For example, "myplugin/mydata.data" - * returns: Output string, or NULL if not found. Use bfree to free string. + * returns: Path string, or NULL if not found. Use bfree to free string. */ EXPORT char *obs_find_plugin_file(const char *file); @@ -214,8 +236,10 @@ EXPORT obs_display_t obs_display_create(struct gs_init_data *graphics_data); EXPORT void obs_display_destroy(obs_display_t display); /** Sets the source to be used for a display context. */ -EXPORT void obs_display_setsource(obs_display_t display, obs_source_t source); -EXPORT obs_source_t obs_display_getsource(obs_display_t display); +EXPORT void obs_display_setsource(obs_display_t display, uint32_t channel, + obs_source_t source); +EXPORT obs_source_t obs_display_getsource(obs_display_t display, + uint32_t channel); /* ------------------------------------------------------------------------- */ @@ -235,7 +259,11 @@ EXPORT const char *obs_source_getdisplayname(enum obs_source_type type, */ EXPORT obs_source_t obs_source_create(enum obs_source_type type, const char *name, const char *settings); -EXPORT void obs_source_destroy(obs_source_t source); +EXPORT void obs_source_addref(obs_source_t source); +EXPORT void obs_source_release(obs_source_t source); + +/** Returns true if the source should be released */ +EXPORT bool obs_source_removed(obs_source_t source); /** * Retrieves flags that specify what type of data the source presents/modifies. @@ -285,7 +313,7 @@ EXPORT bool obs_source_enum_children(obs_source_t source, size_t idx, EXPORT obs_source_t obs_filter_gettarget(obs_source_t filter); /** Adds a filter to the source (which is used whenever the source is used) */ -EXPORT void obs_source_filter_add(obs_source_t source,obs_source_t filter); +EXPORT void obs_source_filter_add(obs_source_t source, obs_source_t filter); /** Removes a filter from the source */ EXPORT void obs_source_filter_remove(obs_source_t source, obs_source_t filter); @@ -393,6 +421,19 @@ EXPORT const char *obs_output_get_settings(obs_output_t output); EXPORT void obs_output_save_settings(obs_output_t output, const char *settings); + +/* ------------------------------------------------------------------------- */ +/* Stream Services */ +EXPORT obs_service_t obs_service_create(const char *service, + const char *settings); +EXPORT void obs_service_destroy(obs_service_t service); + +EXPORT void obs_service_setdata(obs_service_t service, const char *attribute, + const char *data); +EXPORT const char *obs_service_getdata(obs_service_t service, + const char *attribute); + + #ifdef __cplusplus } #endif diff --git a/plugins/obs-outputs/obs-outputs.c b/plugins/obs-outputs/obs-outputs.c index 5cc83cda1..82af58b3c 100644 --- a/plugins/obs-outputs/obs-outputs.c +++ b/plugins/obs-outputs/obs-outputs.c @@ -4,7 +4,7 @@ static const char *outputs[1] = {"rtmp_stream"}; const char *enum_outputs(size_t idx) { - if (idx < sizeof(outputs)/sizeof(const char*)) + if (idx >= sizeof(outputs)/sizeof(const char*)) return NULL; return outputs[idx]; diff --git a/plugins/obs-outputs/obs-outputs.fbp b/plugins/obs-outputs/obs-outputs.fbp new file mode 100644 index 000000000..bd63ec488 --- /dev/null +++ b/plugins/obs-outputs/obs-outputs.fbp @@ -0,0 +1,2590 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + + 1000 + none + 1 + MyProject1 + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + StreamConfig + + 663,546 + wxDEFAULT_DIALOG_STYLE + + StreamConfig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer6 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + + serviceSizer + wxVERTICAL + protected + + 5 + wxEXPAND + 0 + + + bSizer7 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoder + + 0 + + + 0 + 230,-1 + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboBox5 + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Add + + 0 + + + 0 + + 1 + m_button4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Edit + + 0 + + + 0 + + 1 + m_button5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer9 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Service + + 0 + + + 0 + 230,-1 + 1 + m_staticText10 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboBox6 + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer10 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + OK + + 0 + + + 0 + + 1 + m_button7 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Cancel + + 0 + + + 0 + + 1 + m_button8 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + MyPanel2 + + 742,442 + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer19 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + StreamConfig.Encoding.VideoEncoding + + sbSizer2 + wxVERTICAL + none + + + 5 + wxEXPAND + 1 + + 2 + 0 + + gSizer5 + none + 0 + 0 + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.EnableCBR + + 0 + + + 0 + -1,-1 + 1 + m_checkBox1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.CBRPadding + + 0 + + + 0 + -1,-1 + 1 + m_checkBox2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + + + 0 + + fgSizer9 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.Quality + + 0 + + + 0 + 242,-1 + 1 + m_staticText17 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboBox6 + 1 + + + protected + 1 + + Resizable + -1 + 1 + 100,-1 + wxCB_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.CustomBuffer + + 0 + + + 0 + -1,-1 + 1 + m_checkBox3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + + + 0 + + fgSizer10 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.MaxBitrate + + 0 + + + 0 + 242,-1 + 1 + m_staticText19 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrl2 + 1 + + + protected + 1 + + Resizable + 1 + 100,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + + + 0 + + fgSizer15 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.BufferSize + + 0 + + + 0 + 232,-1 + 1 + m_staticText20 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrl3 + 1 + + + protected + 1 + + Resizable + 1 + 100,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + StreamConfig.Encoding.AudioEncoding + + sbSizer3 + wxVERTICAL + none + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + + + 0 + + fgSizer12 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.AudioBitrate + + 0 + + + 0 + 242,-1 + 1 + m_staticText23 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboBox7 + 1 + + + protected + 1 + + Resizable + -1 + 1 + 100,-1 + wxCB_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + + + 0 + + fgSizer13 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Encoding.AudioFormat + + 0 + + + 0 + 242,-1 + 1 + m_staticText24 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboBox8 + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + -1,-1 + DefaultStream + + -1,-1 + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer4 + wxVERTICAL + none + + 0 + + 0 + + 2 + wxBOTH + + + 0 + + fgSizer6 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.Server + + 0 + + + 0 + 230,-1 + 1 + m_staticText12 + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choice1 + 1 + + + protected + 1 + + Resizable + 0 + 1 + 300,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + StreamConfig.StreamKey + + 0 + + + 0 + + 1 + m_staticText13 + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_RIGHT + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_textCtrl1 + 1 + + + protected + 1 + + Resizable + 1 + 300,-1 + wxTE_PASSWORD + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/obs-outputs/obs-stream.h b/plugins/obs-outputs/obs-stream.h index 6e0ef2375..f6f151eba 100644 --- a/plugins/obs-outputs/obs-stream.h +++ b/plugins/obs-outputs/obs-stream.h @@ -4,7 +4,7 @@ #include "obs.h" struct rtmp_stream { - + obs_output_t handler; }; EXPORT void *rtmp_stream_getname(const char *locale); diff --git a/test/osx/test.mm b/test/osx/test.mm index fb6b9791f..e38ea653a 100644 --- a/test/osx/test.mm +++ b/test/osx/test.mm @@ -22,7 +22,7 @@ using SourceContext = std::unique_ptr>; static SourceContext autorelease(obs_source_t s) { - return SourceContext(s, obs_source_destroy); + return SourceContext(s, obs_source_release); } using SceneContext = std::unique_ptr