obs-transitions: Add HDR support to stinger
Regular SDR/HDR stingers, and SDR track matte should work. HDR track matte might work, but would take a carefully crafted video that takes the SDR white level into account, and this hasn't been tested.
This commit is contained in:
parent
8cb57aac1f
commit
6a871d3f66
@ -33,9 +33,9 @@ float3 srgb_nonlinear_to_linear(float3 v)
|
||||
return float3(srgb_nonlinear_to_linear_channel(v.r), srgb_nonlinear_to_linear_channel(v.g), srgb_nonlinear_to_linear_channel(v.b));
|
||||
}
|
||||
|
||||
float4 PSStingerMatte(VertData v_in) : TARGET
|
||||
float4 StingerMatte(VertData f_in)
|
||||
{
|
||||
float2 uv = v_in.uv;
|
||||
float2 uv = f_in.uv;
|
||||
float4 a_color = a_tex.Sample(textureSampler, uv);
|
||||
float4 b_color = b_tex.Sample(textureSampler, uv);
|
||||
float4 matte_color = matte_tex.Sample(textureSampler, uv);
|
||||
@ -51,15 +51,36 @@ float4 PSStingerMatte(VertData v_in) : TARGET
|
||||
matte_luma = (invert_matte ? (1.0 - matte_luma) : matte_luma);
|
||||
|
||||
float4 rgba = lerp(a_color, b_color, matte_luma);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float4 PSStingerMatte(VertData f_in) : TARGET
|
||||
{
|
||||
float4 rgba = StingerMatte(f_in);
|
||||
rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float4 PSStingerMatteLinear(VertData f_in) : TARGET
|
||||
{
|
||||
float4 rgba = StingerMatte(f_in);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
technique StingerMatte
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSStingerMatte(v_in);
|
||||
pixel_shader = PSStingerMatte(f_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique StingerMatteLinear
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSStingerMatteLinear(f_in);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,16 @@ static void stinger_matte_render(void *data, gs_texture_t *a, gs_texture_t *b,
|
||||
float scale_x = (float)cx / matte_cx;
|
||||
float scale_y = (float)cy / matte_cy;
|
||||
|
||||
if (gs_texrender_begin(s->matte_tex, cx, cy)) {
|
||||
const enum gs_color_space space =
|
||||
obs_source_get_color_space(matte_source, 0, NULL);
|
||||
enum gs_color_format format = gs_get_format_from_space(space);
|
||||
if (gs_texrender_get_format(s->matte_tex) != format) {
|
||||
gs_texrender_destroy(s->matte_tex);
|
||||
s->matte_tex = gs_texrender_create(format, GS_ZS_NONE);
|
||||
}
|
||||
|
||||
if (gs_texrender_begin_with_color_space(s->matte_tex, cx, cy,
|
||||
space)) {
|
||||
gs_matrix_scale3f(scale_x, scale_y, 1.0f);
|
||||
gs_matrix_translate3f(width_offset, height_offset,
|
||||
0.0f);
|
||||
@ -273,13 +282,23 @@ static void stinger_matte_render(void *data, gs_texture_t *a, gs_texture_t *b,
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(true);
|
||||
|
||||
gs_effect_set_texture(s->ep_a_tex, a);
|
||||
gs_effect_set_texture(s->ep_b_tex, b);
|
||||
/* texture setters look reversed, but they aren't */
|
||||
const char *tech_name = "StingerMatte";
|
||||
if (gs_get_color_space() == GS_CS_SRGB) {
|
||||
/* users want nonlinear fade */
|
||||
gs_effect_set_texture(s->ep_a_tex, a);
|
||||
gs_effect_set_texture(s->ep_b_tex, b);
|
||||
} else {
|
||||
/* nonlinear fade is too wrong, so use linear fade */
|
||||
gs_effect_set_texture_srgb(s->ep_a_tex, a);
|
||||
gs_effect_set_texture_srgb(s->ep_b_tex, b);
|
||||
tech_name = "StingerMatteLinear";
|
||||
}
|
||||
gs_effect_set_texture(s->ep_matte_tex,
|
||||
gs_texrender_get_texture(s->matte_tex));
|
||||
gs_effect_set_bool(s->ep_invert_matte, s->invert_matte);
|
||||
|
||||
while (gs_effect_loop(s->matte_effect, "StingerMatte"))
|
||||
while (gs_effect_loop(s->matte_effect, tech_name))
|
||||
gs_draw_sprite(NULL, 0, cx, cy);
|
||||
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
@ -289,9 +308,16 @@ static void stinger_matte_render(void *data, gs_texture_t *a, gs_texture_t *b,
|
||||
|
||||
static void stinger_texrender(struct stinger_info *s, uint32_t source_cx,
|
||||
uint32_t source_cy, uint32_t media_cx,
|
||||
uint32_t media_cy)
|
||||
uint32_t media_cy, enum gs_color_space space)
|
||||
{
|
||||
if (gs_texrender_begin(s->stinger_tex, source_cx, source_cy)) {
|
||||
enum gs_color_format format = gs_get_format_from_space(space);
|
||||
if (gs_texrender_get_format(s->stinger_tex) != format) {
|
||||
gs_texrender_destroy(s->stinger_tex);
|
||||
s->stinger_tex = gs_texrender_create(format, GS_ZS_NONE);
|
||||
}
|
||||
|
||||
if (gs_texrender_begin_with_color_space(s->stinger_tex, source_cx,
|
||||
source_cy, space)) {
|
||||
float cx = (float)media_cx / s->matte_width_factor;
|
||||
float cy = (float)media_cy / s->matte_height_factor;
|
||||
|
||||
@ -306,6 +332,50 @@ static void stinger_texrender(struct stinger_info *s, uint32_t source_cx,
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_tech_name_and_multiplier(enum gs_color_space current_space,
|
||||
enum gs_color_space source_space,
|
||||
float *multiplier)
|
||||
{
|
||||
const char *tech_name = "Draw";
|
||||
*multiplier = 1.f;
|
||||
|
||||
switch (source_space) {
|
||||
case GS_CS_SRGB:
|
||||
case GS_CS_SRGB_16F:
|
||||
switch (current_space) {
|
||||
case GS_CS_709_SCRGB:
|
||||
tech_name = "DrawMultiply";
|
||||
*multiplier = obs_get_video_sdr_white_level() / 80.0f;
|
||||
}
|
||||
break;
|
||||
case GS_CS_709_EXTENDED:
|
||||
switch (current_space) {
|
||||
case GS_CS_SRGB:
|
||||
case GS_CS_SRGB_16F:
|
||||
tech_name = "DrawTonemap";
|
||||
break;
|
||||
case GS_CS_709_SCRGB:
|
||||
tech_name = "DrawMultiply";
|
||||
*multiplier = obs_get_video_sdr_white_level() / 80.0f;
|
||||
}
|
||||
break;
|
||||
case GS_CS_709_SCRGB:
|
||||
switch (current_space) {
|
||||
case GS_CS_SRGB:
|
||||
case GS_CS_SRGB_16F:
|
||||
tech_name = "DrawMultiplyTonemap";
|
||||
*multiplier = 80.0f / obs_get_video_sdr_white_level();
|
||||
break;
|
||||
case GS_CS_709_EXTENDED:
|
||||
tech_name = "DrawMultiply";
|
||||
*multiplier = 80.0f / obs_get_video_sdr_white_level();
|
||||
}
|
||||
}
|
||||
|
||||
return tech_name;
|
||||
}
|
||||
|
||||
static void stinger_video_render(void *data, gs_effect_t *effect)
|
||||
{
|
||||
struct stinger_info *s = data;
|
||||
@ -353,21 +423,38 @@ static void stinger_video_render(void *data, gs_effect_t *effect)
|
||||
return;
|
||||
|
||||
if (s->do_texrender) {
|
||||
stinger_texrender(s, source_cx, source_cy, media_cx, media_cy);
|
||||
const enum gs_color_space space =
|
||||
obs_source_get_color_space(s->media_source, 0, NULL);
|
||||
stinger_texrender(s, source_cx, source_cy, media_cx, media_cy,
|
||||
space);
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(true);
|
||||
|
||||
float multiplier;
|
||||
const char *technique = get_tech_name_and_multiplier(
|
||||
gs_get_color_space(), space, &multiplier);
|
||||
|
||||
gs_effect_t *e = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
||||
gs_eparam_t *p = gs_effect_get_param_by_name(e, "image");
|
||||
gs_eparam_t *p_image = gs_effect_get_param_by_name(e, "image");
|
||||
gs_eparam_t *p_multiplier =
|
||||
gs_effect_get_param_by_name(e, "multiplier");
|
||||
gs_texture_t *tex = gs_texrender_get_texture(s->stinger_tex);
|
||||
|
||||
gs_effect_set_texture(p, tex);
|
||||
while (gs_effect_loop(e, "Draw"))
|
||||
gs_effect_set_texture_srgb(p_image, tex);
|
||||
gs_effect_set_float(p_multiplier, multiplier);
|
||||
while (gs_effect_loop(e, technique))
|
||||
gs_draw_sprite(NULL, 0, source_cx, source_cy);
|
||||
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
} else {
|
||||
const bool previous = gs_set_linear_srgb(true);
|
||||
gs_matrix_push();
|
||||
gs_matrix_scale3f(source_cxf / (float)media_cx,
|
||||
source_cyf / (float)media_cy, 1.0f);
|
||||
obs_source_video_render(s->media_source);
|
||||
gs_matrix_pop();
|
||||
gs_set_linear_srgb(previous);
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(effect);
|
||||
@ -792,6 +879,17 @@ static obs_missing_files_t *stinger_missing_files(void *data)
|
||||
return files;
|
||||
}
|
||||
|
||||
static enum gs_color_space
|
||||
stinger_get_color_space(void *data, size_t count,
|
||||
const enum gs_color_space *preferred_spaces)
|
||||
{
|
||||
UNUSED_PARAMETER(count);
|
||||
UNUSED_PARAMETER(preferred_spaces);
|
||||
|
||||
struct stinger_info *s = data;
|
||||
return obs_transition_video_get_color_space(s->source);
|
||||
}
|
||||
|
||||
struct obs_source_info stinger_transition = {
|
||||
.id = "obs_stinger_transition",
|
||||
.type = OBS_SOURCE_TYPE_TRANSITION,
|
||||
@ -809,4 +907,5 @@ struct obs_source_info stinger_transition = {
|
||||
.enum_all_sources = stinger_enum_all_sources,
|
||||
.transition_start = stinger_transition_start,
|
||||
.transition_stop = stinger_transition_stop,
|
||||
.video_get_color_space = stinger_get_color_space,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user