6285a47726
API changed from: obs_source_info::get_name(void) obs_output_info::get_name(void) obs_encoder_info::get_name(void) obs_service_info::get_name(void) API changed to: obs_source_info::get_name(void *type_data) obs_output_info::get_name(void *type_data) obs_encoder_info::get_name(void *type_data) obs_service_info::get_name(void *type_data) This allows the type data to be used when getting the name of the object (useful for plugin wrappers primarily). NOTE: Though a parameter was added, this is backward-compatible with older plugins due to calling convention. The new parameter will simply be ignored by older plugins, and the stack (if used) will be cleaned up by the caller.
226 lines
6.4 KiB
C
226 lines
6.4 KiB
C
#include <obs-module.h>
|
|
#include <graphics/vec2.h>
|
|
|
|
struct crop_filter_data {
|
|
obs_source_t *context;
|
|
|
|
gs_effect_t *effect;
|
|
gs_eparam_t *param_mul;
|
|
gs_eparam_t *param_add;
|
|
|
|
int left;
|
|
int right;
|
|
int top;
|
|
int bottom;
|
|
uint32_t abs_cx;
|
|
uint32_t abs_cy;
|
|
uint32_t width;
|
|
uint32_t height;
|
|
bool absolute;
|
|
};
|
|
|
|
static const char *crop_filter_get_name(void *unused)
|
|
{
|
|
UNUSED_PARAMETER(unused);
|
|
return obs_module_text("CropFilter");
|
|
}
|
|
|
|
static void *crop_filter_create(obs_data_t *settings, obs_source_t *context)
|
|
{
|
|
struct crop_filter_data *filter = bzalloc(sizeof(*filter));
|
|
char *effect_path = obs_module_file("crop_filter.effect");
|
|
|
|
filter->context = context;
|
|
|
|
obs_enter_graphics();
|
|
filter->effect = gs_effect_create_from_file(effect_path, NULL);
|
|
obs_leave_graphics();
|
|
|
|
bfree(effect_path);
|
|
|
|
if (!filter->effect) {
|
|
bfree(filter);
|
|
return NULL;
|
|
}
|
|
|
|
filter->param_mul = gs_effect_get_param_by_name(filter->effect,
|
|
"mul_val");
|
|
filter->param_add = gs_effect_get_param_by_name(filter->effect,
|
|
"add_val");
|
|
|
|
obs_source_update(context, settings);
|
|
return filter;
|
|
}
|
|
|
|
static void crop_filter_destroy(void *data)
|
|
{
|
|
struct crop_filter_data *filter = data;
|
|
|
|
obs_enter_graphics();
|
|
gs_effect_destroy(filter->effect);
|
|
obs_leave_graphics();
|
|
|
|
bfree(filter);
|
|
}
|
|
|
|
static void crop_filter_update(void *data, obs_data_t *settings)
|
|
{
|
|
struct crop_filter_data *filter = data;
|
|
|
|
filter->absolute = !obs_data_get_bool(settings, "relative");
|
|
filter->left = (int)obs_data_get_int(settings, "left");
|
|
filter->top = (int)obs_data_get_int(settings, "top");
|
|
filter->right = (int)obs_data_get_int(settings, "right");
|
|
filter->bottom = (int)obs_data_get_int(settings, "bottom");
|
|
filter->abs_cx = (int)obs_data_get_int(settings, "cx");
|
|
filter->abs_cy = (int)obs_data_get_int(settings, "cy");
|
|
}
|
|
|
|
static bool relative_clicked(obs_properties_t *props, obs_property_t *p,
|
|
obs_data_t *settings)
|
|
{
|
|
bool relative = obs_data_get_bool(settings, "relative");
|
|
|
|
obs_property_set_description(obs_properties_get(props, "left"),
|
|
relative ? obs_module_text("Crop.Left") : "X");
|
|
obs_property_set_description(obs_properties_get(props, "top"),
|
|
relative ? obs_module_text("Crop.Top") : "Y");
|
|
|
|
obs_property_set_visible(obs_properties_get(props, "right"), relative);
|
|
obs_property_set_visible(obs_properties_get(props, "bottom"), relative);
|
|
obs_property_set_visible(obs_properties_get(props, "cx"), !relative);
|
|
obs_property_set_visible(obs_properties_get(props, "cy"), !relative);
|
|
|
|
UNUSED_PARAMETER(p);
|
|
return true;
|
|
}
|
|
|
|
static obs_properties_t *crop_filter_properties(void *data)
|
|
{
|
|
obs_properties_t *props = obs_properties_create();
|
|
|
|
obs_property_t *p = obs_properties_add_bool(props, "relative",
|
|
obs_module_text("Crop.Relative"));
|
|
|
|
obs_property_set_modified_callback(p, relative_clicked);
|
|
|
|
obs_properties_add_int(props, "left", obs_module_text("Crop.Left"),
|
|
0, 8192, 1);
|
|
obs_properties_add_int(props, "top", obs_module_text("Crop.Top"),
|
|
0, 8192, 1);
|
|
obs_properties_add_int(props, "right", obs_module_text("Crop.Right"),
|
|
0, 8192, 1);
|
|
obs_properties_add_int(props, "bottom", obs_module_text("Crop.Bottom"),
|
|
0, 8192, 1);
|
|
obs_properties_add_int(props, "cx", obs_module_text("Crop.Width"),
|
|
0, 8192, 1);
|
|
obs_properties_add_int(props, "cy", obs_module_text("Crop.Height"),
|
|
0, 8192, 1);
|
|
|
|
UNUSED_PARAMETER(data);
|
|
return props;
|
|
}
|
|
|
|
static void crop_filter_defaults(obs_data_t *settings)
|
|
{
|
|
obs_data_set_default_bool(settings, "relative", true);
|
|
}
|
|
|
|
static void calc_crop_dimensions(struct crop_filter_data *filter,
|
|
struct vec2 *mul_val, struct vec2 *add_val)
|
|
{
|
|
obs_source_t *target = obs_filter_get_target(filter->context);
|
|
uint32_t width;
|
|
uint32_t height;
|
|
uint32_t total;
|
|
|
|
if (!target) {
|
|
width = 0;
|
|
height = 0;
|
|
} else {
|
|
width = obs_source_get_base_width(target);
|
|
height = obs_source_get_base_height(target);
|
|
}
|
|
|
|
if (filter->absolute) {
|
|
uint32_t max_abs_cx = (filter->left + filter->abs_cx);
|
|
if (max_abs_cx > width) max_abs_cx = width;
|
|
max_abs_cx -= filter->left;
|
|
|
|
total = max_abs_cx < width ? (width - max_abs_cx) : 0;
|
|
} else {
|
|
total = filter->left + filter->right;
|
|
}
|
|
filter->width = total > width ? 0 : (width - total);
|
|
|
|
if (filter->absolute) {
|
|
uint32_t max_abs_cy = (filter->top + filter->abs_cy);
|
|
if (max_abs_cy > height) max_abs_cy = height;
|
|
max_abs_cy -= filter->top;
|
|
|
|
total = max_abs_cy < height ? (height - max_abs_cy) : 0;
|
|
} else {
|
|
total = filter->top + filter->bottom;
|
|
}
|
|
filter->height = total > height ? 0 : (height - total);
|
|
|
|
if (width && filter->width) {
|
|
mul_val->x = (float)filter->width / (float)width;
|
|
add_val->x = (float)filter->left / (float)width;
|
|
}
|
|
|
|
if (height && filter->height) {
|
|
mul_val->y = (float)filter->height / (float)height;
|
|
add_val->y = (float)filter->top / (float)height;
|
|
}
|
|
}
|
|
|
|
static void crop_filter_render(void *data, gs_effect_t *effect)
|
|
{
|
|
struct crop_filter_data *filter = data;
|
|
struct vec2 mul_val;
|
|
struct vec2 add_val;
|
|
|
|
vec2_zero(&mul_val);
|
|
vec2_zero(&add_val);
|
|
calc_crop_dimensions(filter, &mul_val, &add_val);
|
|
|
|
obs_source_process_filter_begin(filter->context, GS_RGBA,
|
|
OBS_NO_DIRECT_RENDERING);
|
|
|
|
gs_effect_set_vec2(filter->param_mul, &mul_val);
|
|
gs_effect_set_vec2(filter->param_add, &add_val);
|
|
|
|
obs_source_process_filter_end(filter->context, filter->effect,
|
|
filter->width, filter->height);
|
|
|
|
UNUSED_PARAMETER(effect);
|
|
}
|
|
|
|
static uint32_t crop_filter_width(void *data)
|
|
{
|
|
struct crop_filter_data *crop = data;
|
|
return crop->width;
|
|
}
|
|
|
|
static uint32_t crop_filter_height(void *data)
|
|
{
|
|
struct crop_filter_data *crop = data;
|
|
return crop->height;
|
|
}
|
|
|
|
struct obs_source_info crop_filter = {
|
|
.id = "crop_filter",
|
|
.type = OBS_SOURCE_TYPE_FILTER,
|
|
.output_flags = OBS_SOURCE_VIDEO,
|
|
.get_name = crop_filter_get_name,
|
|
.create = crop_filter_create,
|
|
.destroy = crop_filter_destroy,
|
|
.update = crop_filter_update,
|
|
.get_properties = crop_filter_properties,
|
|
.get_defaults = crop_filter_defaults,
|
|
.video_render = crop_filter_render,
|
|
.get_width = crop_filter_width,
|
|
.get_height = crop_filter_height
|
|
};
|