mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-04 10:33:30 +00:00
libobs: Add VIDEO_FORMAT_V210
Support 10-bit packed format that DeckLink uses.
This commit is contained in:
parent
5d287734a8
commit
97843dd7d7
|
@ -58,6 +58,8 @@ Video Handler
|
|||
|
||||
- VIDEO_FORMAT_P416
|
||||
|
||||
- VIDEO_FORMAT_V210
|
||||
|
||||
---------------------
|
||||
|
||||
.. enum:: video_trc
|
||||
|
|
|
@ -807,6 +807,9 @@ Functions used by outputs
|
|||
|
||||
/* planar 4:4:4 format, 16 bpp */
|
||||
VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
|
||||
|
||||
/* packed 4:2:2 format, 10 bpp */
|
||||
VIDEO_FORMAT_V210,
|
||||
};
|
||||
|
||||
enum video_colorspace {
|
||||
|
|
|
@ -1447,6 +1447,9 @@ Functions used by sources
|
|||
|
||||
/* planar 4:4:4 format, 16 bpp */
|
||||
VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
|
||||
|
||||
/* packed 4:2:2 format, 10 bpp */
|
||||
VIDEO_FORMAT_V210,
|
||||
};
|
||||
|
||||
struct obs_source_frame {
|
||||
|
|
|
@ -925,6 +925,92 @@ float4 PSP010_HLG_2020_709_Reverse(VertTexPos frag_in) : TARGET
|
|||
return float4(rgb, 1.);
|
||||
}
|
||||
|
||||
float3 compute_v210_reverse(float2 pos)
|
||||
{
|
||||
uint x = (uint)pos.x;
|
||||
uint packed_x = x % 6;
|
||||
uint base_x = (x / 6) * 4;
|
||||
float y, cb, cr;
|
||||
if (packed_x == 0)
|
||||
{
|
||||
float3 word0_rgb = image.Load(int3(base_x, pos.y, 0)).rgb;
|
||||
y = word0_rgb.y;
|
||||
cb = word0_rgb.x;
|
||||
cr = word0_rgb.z;
|
||||
}
|
||||
else if (packed_x == 1)
|
||||
{
|
||||
float2 word0_rb = image.Load(int3(base_x, pos.y, 0)).rb;
|
||||
float2 word1_rg = image.Load(int3(base_x + 1, pos.y, 0)).rg;
|
||||
y = word1_rg.x;
|
||||
cb = (word0_rb.x + word1_rg.y) * 0.5;
|
||||
cr = (word0_rb.y + image.Load(int3(base_x + 2, pos.y, 0)).r) * 0.5;
|
||||
}
|
||||
else if (packed_x == 2)
|
||||
{
|
||||
float2 word1_gb = image.Load(int3(base_x + 1, pos.y, 0)).gb;
|
||||
y = word1_gb.y;
|
||||
cb = word1_gb.x;
|
||||
cr = image.Load(int3(base_x + 2, pos.y, 0)).r;
|
||||
}
|
||||
else if (packed_x == 3)
|
||||
{
|
||||
float2 word2_rb = image.Load(int3(base_x + 2, pos.y, 0)).rb;
|
||||
y = image.Load(int3(base_x + 2, pos.y, 0)).g;
|
||||
cb = (image.Load(int3(base_x + 1, pos.y, 0)).g + word2_rb.y) * 0.5;
|
||||
cr = (word2_rb.x + image.Load(int3(base_x + 3, pos.y, 0)).g) * 0.5;
|
||||
}
|
||||
else if (packed_x == 4)
|
||||
{
|
||||
float2 word3_rg = image.Load(int3(base_x + 3, pos.y, 0)).rg;
|
||||
y = word3_rg.x;
|
||||
cb = image.Load(int3(base_x + 2, pos.y, 0)).b;
|
||||
cr = word3_rg.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
float2 word3_gb = image.Load(int3(base_x + 3, pos.y, 0)).gb;
|
||||
y = word3_gb.y;
|
||||
cb = image.Load(int3(base_x + 2, pos.y, 0)).b;
|
||||
cr = word3_gb.x;
|
||||
uint base_x_4 = base_x + 4;
|
||||
if ((pos.x + 1.) < width)
|
||||
{
|
||||
float2 word4_gb = image.Load(int3(base_x + 4, pos.y, 0)).rb;
|
||||
cb = (cb + word4_gb.x) * 0.5;
|
||||
cr = (cr + word4_gb.y) * 0.5;
|
||||
}
|
||||
}
|
||||
float3 yuv_65535 = floor(float3(y, cb, cr) * 65535. + 0.5);
|
||||
float3 yuv_1023 = floor(yuv_65535 * 0.015625);
|
||||
float3 yuv = yuv_1023 / 1023.;
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSV210_SRGB_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
float3 rgb = compute_v210_reverse(frag_in.pos);
|
||||
rgb = srgb_nonlinear_to_linear(rgb);
|
||||
return float4(rgb, 1.);
|
||||
}
|
||||
|
||||
float4 PSV210_PQ_2020_709_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
float3 pq = compute_v210_reverse(frag_in.pos);
|
||||
float3 hdr2020 = st2084_to_linear_eetf(pq, hdr_lw, hdr_lmax) * maximum_over_sdr_white_nits;
|
||||
float3 rgb = rec2020_to_rec709(hdr2020);
|
||||
return float4(rgb, 1.);
|
||||
}
|
||||
|
||||
float4 PSV210_HLG_2020_709_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
float3 hlg = compute_v210_reverse(frag_in.pos);
|
||||
float3 hdr2020 = hlg_to_linear(hlg, hlg_exponent) * maximum_over_sdr_white_nits;
|
||||
float3 rgb = rec2020_to_rec709(hdr2020);
|
||||
return float4(rgb, 1.);
|
||||
}
|
||||
|
||||
float3 PSY800_Limited(FragPos frag_in) : TARGET
|
||||
{
|
||||
float limited = image.Load(int3(frag_in.pos.xy, 0)).x;
|
||||
|
@ -1544,6 +1630,33 @@ technique P010_HLG_2020_709_Reverse
|
|||
}
|
||||
}
|
||||
|
||||
technique V210_SRGB_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSV210_SRGB_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique V210_PQ_2020_709_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSV210_PQ_2020_709_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique V210_HLG_2020_709_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSV210_HLG_2020_709_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique Y800_Limited
|
||||
{
|
||||
pass
|
||||
|
|
|
@ -330,6 +330,15 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
|||
frame->linesize[1] = width * 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_V210: {
|
||||
const uint32_t adjusted_width = ((width + 5) / 6) * 16;
|
||||
size = adjusted_width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->linesize[0] = adjusted_width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,9 @@ enum video_format {
|
|||
|
||||
/* planar 4:4:4 format, 16 bpp */
|
||||
VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
|
||||
|
||||
/* packed 4:2:2 format, 10 bpp */
|
||||
VIDEO_FORMAT_V210,
|
||||
};
|
||||
|
||||
enum video_trc {
|
||||
|
@ -153,6 +156,7 @@ static inline bool format_is_yuv(enum video_format format)
|
|||
case VIDEO_FORMAT_P010:
|
||||
case VIDEO_FORMAT_P216:
|
||||
case VIDEO_FORMAT_P416:
|
||||
case VIDEO_FORMAT_V210:
|
||||
return true;
|
||||
case VIDEO_FORMAT_NONE:
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
|
@ -215,6 +219,8 @@ static inline const char *get_video_format_name(enum video_format format)
|
|||
return "P216";
|
||||
case VIDEO_FORMAT_P416:
|
||||
return "P416";
|
||||
case VIDEO_FORMAT_V210:
|
||||
return "V210";
|
||||
case VIDEO_FORMAT_NONE:;
|
||||
}
|
||||
|
||||
|
|
|
@ -263,6 +263,7 @@ bool video_format_get_parameters_for_format(enum video_colorspace color_space,
|
|||
case VIDEO_FORMAT_I010:
|
||||
case VIDEO_FORMAT_P010:
|
||||
case VIDEO_FORMAT_I210:
|
||||
case VIDEO_FORMAT_V210:
|
||||
bpc = 10;
|
||||
break;
|
||||
case VIDEO_FORMAT_I412:
|
||||
|
|
|
@ -1591,6 +1591,7 @@ enum convert_type {
|
|||
CONVERT_BGR3,
|
||||
CONVERT_I010,
|
||||
CONVERT_P010,
|
||||
CONVERT_V210,
|
||||
};
|
||||
|
||||
static inline enum convert_type get_convert_type(enum video_format format,
|
||||
|
@ -1648,6 +1649,9 @@ static inline enum convert_type get_convert_type(enum video_format format,
|
|||
case VIDEO_FORMAT_P010:
|
||||
return CONVERT_P010;
|
||||
|
||||
case VIDEO_FORMAT_V210:
|
||||
return CONVERT_V210;
|
||||
|
||||
case VIDEO_FORMAT_P216:
|
||||
case VIDEO_FORMAT_P416:
|
||||
/* Unimplemented */
|
||||
|
@ -1942,6 +1946,19 @@ static inline bool set_p010_sizes(struct obs_source *source,
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline bool set_v210_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t adjusted_width = ((width + 5) / 6) * 4;
|
||||
source->async_convert_width[0] = adjusted_width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_texture_formats[0] = GS_R10G10B10A2;
|
||||
source->async_channel_count = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool init_gpu_conversion(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
|
@ -1999,6 +2016,9 @@ static inline bool init_gpu_conversion(struct obs_source *source,
|
|||
case CONVERT_P010:
|
||||
return set_p010_sizes(source, frame);
|
||||
|
||||
case CONVERT_V210:
|
||||
return set_v210_sizes(source, frame);
|
||||
|
||||
case CONVERT_NONE:
|
||||
assert(false && "No conversion requested");
|
||||
break;
|
||||
|
@ -2091,6 +2111,7 @@ static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
|
|||
case CONVERT_444_A_PACK:
|
||||
case CONVERT_I010:
|
||||
case CONVERT_P010:
|
||||
case CONVERT_V210:
|
||||
for (size_t c = 0; c < MAX_AV_PLANES; c++) {
|
||||
if (tex[c])
|
||||
gs_texture_set_image(tex[c], frame->data[c],
|
||||
|
@ -2213,6 +2234,17 @@ static const char *select_conversion_technique(enum video_format format,
|
|||
}
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_V210: {
|
||||
switch (trc) {
|
||||
case VIDEO_TRC_PQ:
|
||||
return "V210_PQ_2020_709_Reverse";
|
||||
case VIDEO_TRC_HLG:
|
||||
return "V210_HLG_2020_709_Reverse";
|
||||
default:
|
||||
return "V210_SRGB_Reverse";
|
||||
}
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
|
@ -3373,6 +3405,7 @@ static void copy_frame_data(struct obs_source_frame *dst,
|
|||
case VIDEO_FORMAT_Y800:
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
case VIDEO_FORMAT_V210:
|
||||
copy_frame_data_plane(dst, src, 0, dst->height);
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in a new issue