From 778cc2b3182d1273eb3de5a9a33d9b4190bff02a Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sun, 20 Jul 2014 17:40:57 -0700 Subject: [PATCH] (API Change) obs_reset_video: Use return codes Changed API functions: libobs: obs_reset_video Before, video initialization returned a boolean, but "failed" is too little information, if it fails due to lack of device capabilities or bad video device parameters, the front-end needs to know that. The OBS Basic UI has also been updated to reflect this API change. --- libobs-d3d11/d3d11-subsystem.cpp | 27 ++++++-- libobs-opengl/gl-subsystem.c | 14 ++-- libobs/graphics/device-exports.h | 2 +- libobs/graphics/graphics-internal.h | 2 +- libobs/graphics/graphics.c | 10 +-- libobs/graphics/graphics.h | 5 +- libobs/obs-defs.h | 7 ++ libobs/obs.c | 103 ++++++++++++++++------------ libobs/obs.h | 17 ++++- obs/window-basic-main.cpp | 29 ++++++-- obs/window-basic-main.hpp | 2 +- test/osx/test.mm | 2 +- test/win/test.cpp | 2 +- 13 files changed, 150 insertions(+), 72 deletions(-) diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index b4b19f4c8..ddb2d25bc 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -20,6 +20,13 @@ #include #include "d3d11-subsystem.hpp" +struct UnsupportedHWError : HRError { + inline UnsupportedHWError(const char *str, HRESULT hr) + : HRError(str, hr) + { + } +}; + #ifdef _MSC_VER /* alignment warning - despite the fact that alignment is already fixed */ #pragma warning (disable : 4316) @@ -136,11 +143,11 @@ void gs_device::InitFactory(uint32_t adapterIdx, IDXGIAdapter1 **padapter) hr = CreateDXGIFactory1(factoryIID, (void**)factory.Assign()); if (FAILED(hr)) - throw HRError("Failed to create DXGIFactory", hr); + throw UnsupportedHWError("Failed to create DXGIFactory", hr); hr = factory->EnumAdapters1(adapterIdx, padapter); if (FAILED(hr)) - throw HRError("Failed to enumerate DXGIAdapter", hr); + throw UnsupportedHWError("Failed to enumerate DXGIAdapter", hr); } const static D3D_FEATURE_LEVEL featureLevels[] = @@ -181,7 +188,8 @@ void gs_device::InitDevice(gs_init_data *data, IDXGIAdapter *adapter) defaultSwap.swap.Assign(), device.Assign(), &levelUsed, context.Assign()); if (FAILED(hr)) - throw HRError("Failed to create device and swap chain", hr); + throw UnsupportedHWError("Failed to create device and " + "swap chain", hr); blog(LOG_INFO, "D3D11 loaded sucessfully, feature level used: %u", (uint32_t)levelUsed); @@ -433,18 +441,27 @@ const char *device_preprocessor_name(void) return "_D3D11"; } -gs_device *device_create(gs_init_data *data) +int device_create(device_t *p_device, gs_init_data *data) { gs_device *device = NULL; + int errorcode = GS_SUCCESS; try { device = new gs_device(data); + + } catch (UnsupportedHWError error) { + blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str, + error.hr); + errorcode = GS_ERROR_NOT_SUPPORTED; + } catch (HRError error) { blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str, error.hr); + errorcode = GS_ERROR_FAIL; } - return device; + *p_device = device; + return errorcode; } void device_destroy(device_t device) diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index 84f0e989e..44b319e60 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -197,16 +197,19 @@ const char *device_preprocessor_name(void) return "_OPENGL"; } -device_t device_create(struct gs_init_data *info) +int device_create(device_t *p_device, struct gs_init_data *info) { struct gs_device *device = bzalloc(sizeof(struct gs_device)); + int errorcode = GS_ERROR_FAIL; device->plat = gl_platform_create(device, info); if (!device->plat) goto fail; - if (!gl_init_extensions(device)) + if (!gl_init_extensions(device)) { + errorcode = GS_ERROR_NOT_SUPPORTED; goto fail; + } gl_enable(GL_CULL_FACE); @@ -221,12 +224,15 @@ device_t device_create(struct gs_init_data *info) device_leavecontext(device); device->cur_swap = gl_platform_getswap(device->plat); - return device; + *p_device = device; + return GS_SUCCESS; fail: blog(LOG_ERROR, "device_create (GL) failed"); bfree(device); - return NULL; + + *p_device = NULL; + return errorcode; } void device_destroy(device_t device) diff --git a/libobs/graphics/device-exports.h b/libobs/graphics/device-exports.h index 50eb67979..4852d9f8e 100644 --- a/libobs/graphics/device-exports.h +++ b/libobs/graphics/device-exports.h @@ -26,7 +26,7 @@ extern "C" { EXPORT const char *device_name(void); EXPORT int device_type(void); EXPORT const char *device_preprocessor_name(void); -EXPORT device_t device_create(struct gs_init_data *data); +EXPORT int device_create(device_t *device, struct gs_init_data *data); EXPORT void device_destroy(device_t device); EXPORT void device_entercontext(device_t device); EXPORT void device_leavecontext(device_t device); diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h index 626d45353..457882c8b 100644 --- a/libobs/graphics/graphics-internal.h +++ b/libobs/graphics/graphics-internal.h @@ -27,7 +27,7 @@ struct gs_exports { const char *(*device_name)(void); int (*device_type)(void); const char *(*device_preprocessor_name)(void); - device_t (*device_create)(struct gs_init_data *data); + int (*device_create)(device_t *device, struct gs_init_data *data); void (*device_destroy)(device_t device); void (*device_entercontext)(device_t device); void (*device_leavecontext)(device_t device); diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index 2849c73b4..d55775910 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -137,15 +137,17 @@ int gs_create(graphics_t *pgraphics, const char *module, module)) goto error; - graphics->device = graphics->exports.device_create(data); - if (!graphics->device) + errcode = graphics->exports.device_create(&graphics->device, data); + if (errcode != GS_SUCCESS) goto error; - if (!graphics_init(graphics)) + if (!graphics_init(graphics)) { + errcode = GS_ERROR_FAIL; goto error; + } *pgraphics = graphics; - return GS_SUCCESS; + return errcode; error: gs_destroy(graphics); diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 6ff4fe2ff..4404c2747 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -392,8 +392,9 @@ EXPORT texture_t texrender_gettexture(texrender_t texrender); /* global functions */ #define GS_SUCCESS 0 -#define GS_ERROR_MODULE_NOT_FOUND -1 -#define GS_ERROR_FAIL -2 +#define GS_ERROR_FAIL -1 +#define GS_ERROR_MODULE_NOT_FOUND -2 +#define GS_ERROR_NOT_SUPPORTED -3 struct gs_window { #if defined(_WIN32) diff --git a/libobs/obs-defs.h b/libobs/obs-defs.h index f2c9717e7..c755cdc65 100644 --- a/libobs/obs-defs.h +++ b/libobs/obs-defs.h @@ -38,3 +38,10 @@ #define OBS_OUTPUT_INVALID_STREAM -3 #define OBS_OUTPUT_ERROR -4 #define OBS_OUTPUT_DISCONNECTED -5 + +#define OBS_VIDEO_SUCCESS 0 +#define OBS_VIDEO_FAIL -1 +#define OBS_VIDEO_NOT_SUPPORTED -2 +#define OBS_VIDEO_INVALID_PARAM -3 +#define OBS_VIDEO_CURRENTLY_ACTIVE -4 +#define OBS_VIDEO_MODULE_NOT_FOUND -5 diff --git a/libobs/obs.c b/libobs/obs.c index d92d90094..375ec00c0 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -192,7 +192,7 @@ static bool obs_init_textures(struct obs_video_info *ovi) return true; } -static bool obs_init_graphics(struct obs_video_info *ovi) +static int obs_init_graphics(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; struct gs_init_data graphics_data; @@ -204,43 +204,45 @@ static bool obs_init_graphics(struct obs_video_info *ovi) errorcode = gs_create(&video->graphics, ovi->graphics_module, &graphics_data); if (errorcode != GS_SUCCESS) { - if (errorcode == GS_ERROR_MODULE_NOT_FOUND) - blog(LOG_ERROR, "Could not find graphics module '%s'", - ovi->graphics_module); - return false; + switch (errorcode) { + case GS_ERROR_MODULE_NOT_FOUND: + return OBS_VIDEO_MODULE_NOT_FOUND; + case GS_ERROR_NOT_SUPPORTED: + return OBS_VIDEO_NOT_SUPPORTED; + default: + return OBS_VIDEO_FAIL; + } } gs_entercontext(video->graphics); - if (success) { - char *filename = find_libobs_data_file("default.effect"); - video->default_effect = gs_create_effect_from_file(filename, - NULL); - bfree(filename); + char *filename = find_libobs_data_file("default.effect"); + video->default_effect = gs_create_effect_from_file(filename, + NULL); + bfree(filename); - filename = find_libobs_data_file("solid.effect"); - video->solid_effect = gs_create_effect_from_file(filename, - NULL); - bfree(filename); + filename = find_libobs_data_file("solid.effect"); + video->solid_effect = gs_create_effect_from_file(filename, + NULL); + bfree(filename); - filename = find_libobs_data_file("format_conversion.effect"); - video->conversion_effect = gs_create_effect_from_file(filename, - NULL); - bfree(filename); + filename = find_libobs_data_file("format_conversion.effect"); + video->conversion_effect = gs_create_effect_from_file(filename, + NULL); + bfree(filename); - if (!video->default_effect) - success = false; - if (!video->solid_effect) - success = false; - if (!video->conversion_effect) - success = false; - } + if (!video->default_effect) + success = false; + if (!video->solid_effect) + success = false; + if (!video->conversion_effect) + success = false; gs_leavecontext(); - return success; + return success ? OBS_VIDEO_SUCCESS : OBS_VIDEO_FAIL; } -static bool obs_init_video(struct obs_video_info *ovi) +static int obs_init_video(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; struct video_output_info vi; @@ -256,16 +258,17 @@ static bool obs_init_video(struct obs_video_info *ovi) errorcode = video_output_open(&video->video, &vi); if (errorcode != VIDEO_OUTPUT_SUCCESS) { - if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) + if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) { blog(LOG_ERROR, "Invalid video parameters specified"); - else + return OBS_VIDEO_INVALID_PARAM; + } else { blog(LOG_ERROR, "Could not open video output"); - - return false; + } + return OBS_VIDEO_FAIL; } if (!obs_display_init(&video->main_display, NULL)) - return false; + return OBS_VIDEO_FAIL; video->main_display.cx = ovi->window_width; video->main_display.cy = ovi->window_height; @@ -273,19 +276,19 @@ static bool obs_init_video(struct obs_video_info *ovi) gs_entercontext(video->graphics); if (ovi->gpu_conversion && !obs_init_gpu_conversion(ovi)) - return false; + return OBS_VIDEO_FAIL; if (!obs_init_textures(ovi)) - return false; + return OBS_VIDEO_FAIL; gs_leavecontext(); errorcode = pthread_create(&video->video_thread, NULL, obs_video_thread, obs); if (errorcode != 0) - return false; + return OBS_VIDEO_FAIL; video->thread_initialized = true; - return true; + return OBS_VIDEO_SUCCESS; } static void stop_video(void) @@ -597,13 +600,26 @@ const char *obs_get_locale(void) return obs ? obs->locale : NULL; } -bool obs_reset_video(struct obs_video_info *ovi) +#define OBS_SIZE_MIN 2 +#define OBS_SIZE_MAX (32 * 1024) + +static inline bool size_valid(uint32_t width, uint32_t height) { - if (!obs) return false; + return (width >= OBS_SIZE_MIN && height >= OBS_SIZE_MIN && + width <= OBS_SIZE_MAX && height <= OBS_SIZE_MAX); +} + +int obs_reset_video(struct obs_video_info *ovi) +{ + if (!obs) return OBS_VIDEO_FAIL; /* don't allow changing of video settings if active. */ if (obs->video.video && video_output_active(obs->video.video)) - return false; + return OBS_VIDEO_CURRENTLY_ACTIVE; + + if (!size_valid(ovi->output_width, ovi->output_height) || + !size_valid(ovi->base_width, ovi->base_height)) + return OBS_VIDEO_INVALID_PARAM; struct obs_core_video *video = &obs->video; @@ -612,15 +628,18 @@ bool obs_reset_video(struct obs_video_info *ovi) if (!ovi) { obs_free_graphics(); - return true; + return OBS_VIDEO_SUCCESS; } /* align to multiple-of-two and SSE alignment sizes */ ovi->output_width &= 0xFFFFFFFC; ovi->output_height &= 0xFFFFFFFE; - if (!video->graphics && !obs_init_graphics(ovi)) - return false; + if (!video->graphics) { + int errorcode = obs_init_graphics(ovi); + if (errorcode != OBS_VIDEO_SUCCESS) + return errorcode; + } blog(LOG_INFO, "video settings reset:\n" "\tbase resolution: %dx%d\n" diff --git a/libobs/obs.h b/libobs/obs.h index 012d9a025..7753a6c7e 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -223,11 +223,22 @@ EXPORT void obs_set_locale(const char *locale); EXPORT const char *obs_get_locale(void); /** - * Sets base video ouput base resolution/fps/format + * Sets base video ouput base resolution/fps/format. * - * @note Cannot set base video if an output is currently active. + * @note This data cannot be changed if an output is corrently active. + * @note The graphics module cannot be changed without fully destroying the + * OBS context. + * + * @param ovi Pointer to an obs_video_info structure containing the + * specification of the graphics subsystem, + * @return OBS_VIDEO_SUCCESS if sucessful + * OBS_VIDEO_NOT_SUPPORTED if the adapter lacks capabilities + * OBS_VIDEO_INVALID_PARAM if a parameter is invalid + * OBS_VIDEO_CURRENTLY_ACTIVE if video is currently active + * OBS_VIDEO_MODULE_NOT_FOUND if the graphics module is not found + * OBS_VIDEO_FAIL for generic failure */ -EXPORT bool obs_reset_video(struct obs_video_info *ovi); +EXPORT int obs_reset_video(struct obs_video_info *ovi); /** * Sets base audio output format/channels/samples/etc diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 309bcce00..83aca7360 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -513,11 +513,25 @@ void OBSBasic::OBSInit() throw "Failed to initialize libobs"; if (!InitBasicConfig()) throw "Failed to load basic.ini"; - if (!ResetVideo()) - throw "Failed to initialize video"; if (!ResetAudio()) throw "Failed to initialize audio"; + int ret = ResetVideo(); + + switch (ret) { + case OBS_VIDEO_MODULE_NOT_FOUND: + throw "Failed to initialize video: Graphics module not found"; + case OBS_VIDEO_NOT_SUPPORTED: + throw "Failed to initialize video: Your graphics adapter " + "is either too old or does not have the required " + "capabilities required for this program"; + case OBS_VIDEO_INVALID_PARAM: + throw "Failed to initialize video: Invalid parameters"; + default: + if (ret != OBS_VIDEO_SUCCESS) + throw "Failed to initialize video: Unspecified error"; + } + InitOBSCallbacks(); /* TODO: this is a test, all modules will be searched for and loaded @@ -1182,9 +1196,10 @@ void OBSBasic::SetService(obs_service_t newService) } } -bool OBSBasic::ResetVideo() +int OBSBasic::ResetVideo() { struct obs_video_info ovi; + int ret; GetConfigFPS(ovi.fps_num, ovi.fps_den); @@ -1210,11 +1225,11 @@ bool OBSBasic::ResetVideo() ovi.window_width = size.width(); ovi.window_height = size.height(); - if (!obs_reset_video(&ovi)) - return false; + ret = obs_reset_video(&ovi); + if (ret == OBS_VIDEO_SUCCESS) + obs_add_draw_callback(OBSBasic::RenderMain, this); - obs_add_draw_callback(OBSBasic::RenderMain, this); - return true; + return ret; } bool OBSBasic::ResetAudio() diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp index af90b2961..673ee99f2 100644 --- a/obs/window-basic-main.hpp +++ b/obs/window-basic-main.hpp @@ -191,7 +191,7 @@ public: obs_service_t GetService(); void SetService(obs_service_t service); - bool ResetVideo(); + int ResetVideo(); bool ResetAudio(); void ResetAudioDevice(const char *sourceId, const char *deviceName, diff --git a/test/osx/test.mm b/test/osx/test.mm index df03c3de6..02a39179b 100644 --- a/test/osx/test.mm +++ b/test/osx/test.mm @@ -55,7 +55,7 @@ static void CreateOBS(NSView *view) ovi.window_height = cy; ovi.window.view = view; - if (!obs_reset_video(&ovi)) + if (obs_reset_video(&ovi) != 0) throw "Couldn't initialize video"; } diff --git a/test/win/test.cpp b/test/win/test.cpp index cf547fb34..c9abea957 100644 --- a/test/win/test.cpp +++ b/test/win/test.cpp @@ -88,7 +88,7 @@ static void CreateOBS(HWND hwnd) ovi.output_height = rc.bottom; ovi.window.hwnd = hwnd; - if (!obs_reset_video(&ovi)) + if (obs_reset_video(&ovi) != 0) throw "Couldn't initialize video"; }