Przeglądaj źródła

(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.
jp9000 11 lat temu
rodzic
commit
778cc2b318

+ 22 - 5
libobs-d3d11/d3d11-subsystem.cpp

@@ -20,6 +20,13 @@
 #include <graphics/matrix3.h>
 #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)

+ 10 - 4
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)

+ 1 - 1
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);

+ 1 - 1
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);

+ 6 - 4
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);

+ 3 - 2
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)

+ 7 - 0
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

+ 64 - 45
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);
-
-		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);
-
-		if (!video->default_effect)
-			success = false;
-		if (!video->solid_effect)
-			success = false;
-		if (!video->conversion_effect)
-			success = false;
-	}
+	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("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;
 
 	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"

+ 14 - 3
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

+ 22 - 7
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()

+ 1 - 1
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,

+ 1 - 1
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";
 }
 

+ 1 - 1
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";
 }