From 463bf0dff59a452edf66bbdb3ab20995bcfd25b1 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Sun, 20 Nov 2022 19:11:27 -0800 Subject: [PATCH] libobs,UI: Add P216/P416 pixel formats Will be useful for ProRes. --- UI/data/locale/en-US.ini | 4 +- UI/window-basic-main.cpp | 4 + UI/window-basic-settings.cpp | 12 +- docs/sphinx/reference-libobs-media-io.rst | 10 + docs/sphinx/reference-outputs.rst | 15 ++ docs/sphinx/reference-sources.rst | 15 ++ libobs/data/format_conversion.effect | 230 ++++++++++++++++++++++ libobs/media-io/video-frame.c | 33 ++++ libobs/media-io/video-io.h | 24 ++- libobs/media-io/video-matrices.c | 4 + libobs/media-io/video-scaler-ffmpeg.c | 14 +- libobs/obs-internal.h | 2 + libobs/obs-video.c | 27 +++ libobs/obs.c | 84 +++++++- plugins/obs-ffmpeg/obs-ffmpeg-formats.h | 6 + 15 files changed, 466 insertions(+), 18 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index a0423ce64..7a6d40a0f 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -1148,7 +1148,7 @@ Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Below Normal" Basic.Settings.Advanced.General.ProcessPriority.Idle="Idle" Basic.Settings.Advanced.FormatWarning="Warning: Color formats other than NV12/P010 are primarily intended for recording, and are not recommended when streaming. Streaming may incur increased CPU usage due to color format conversion." -Basic.Settings.Advanced.FormatWarning10BitSdr="Warning: 10-bit formats are more commonly used with HDR color spaces." +Basic.Settings.Advanced.FormatWarningPreciseSdr="Warning: High-precision formats are more commonly used with HDR color spaces." Basic.Settings.Advanced.FormatWarning2100="Warning: Rec. 2100 should use a format with more precision." Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time" Basic.Settings.Advanced.Video.ColorFormat="Color Format" @@ -1157,6 +1157,8 @@ Basic.Settings.Advanced.Video.ColorFormat.I420="I420 (8-bit, 4:2:0, 3 planes)" Basic.Settings.Advanced.Video.ColorFormat.I444="I444 (8-bit, 4:4:4, 3 planes)" Basic.Settings.Advanced.Video.ColorFormat.P010="P010 (10-bit, 4:2:0, 2 planes)" Basic.Settings.Advanced.Video.ColorFormat.I010="I010 (10-bit, 4:2:0, 3 planes)" +Basic.Settings.Advanced.Video.ColorFormat.P216="P216 (16-bit, 4:2:2, 2 planes)" +Basic.Settings.Advanced.Video.ColorFormat.P416="P416 (16-bit, 4:4:4, 2 planes)" Basic.Settings.Advanced.Video.ColorFormat.BGRA="BGRA (8-bit)" Basic.Settings.Advanced.Video.ColorSpace="Color Space" Basic.Settings.Advanced.Video.ColorSpace.sRGB="sRGB" diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index b5569978c..5f537befe 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -4393,6 +4393,10 @@ static inline enum video_format GetVideoFormatFromName(const char *name) return VIDEO_FORMAT_I010; else if (astrcmpi(name, "P010") == 0) return VIDEO_FORMAT_P010; + else if (astrcmpi(name, "P216") == 0) + return VIDEO_FORMAT_P216; + else if (astrcmpi(name, "P416") == 0) + return VIDEO_FORMAT_P416; #if 0 //currently unsupported else if (astrcmpi(name, "YVYU") == 0) return VIDEO_FORMAT_YVYU; diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 6ada5f496..e1c5a32a4 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1006,6 +1006,8 @@ void OBSBasicSettings::LoadColorSpaces() #define CF_I444_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I444") #define CF_P010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P010") #define CF_I010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I010") +#define CF_P216_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P216") +#define CF_P416_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P416") #define CF_BGRA_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.BGRA") void OBSBasicSettings::LoadColorFormats() @@ -1015,6 +1017,8 @@ void OBSBasicSettings::LoadColorFormats() ui->colorFormat->addItem(CF_I444_STR, "I444"); ui->colorFormat->addItem(CF_P010_STR, "P010"); ui->colorFormat->addItem(CF_I010_STR, "I010"); + ui->colorFormat->addItem(CF_P216_STR, "P216"); + ui->colorFormat->addItem(CF_P416_STR, "P416"); ui->colorFormat->addItem(CF_BGRA_STR, "RGB"); // Avoid config break } @@ -2599,7 +2603,8 @@ void OBSBasicSettings::UpdateColorFormatSpaceWarning() switch (ui->colorSpace->currentIndex()) { case 3: /* Rec.2100 (PQ) */ case 4: /* Rec.2100 (HLG) */ - if (format == "P010") { + if ((format == "P010") || (format == "P216") || + (format == "P416")) { ui->advancedMsg2->clear(); } else if (format == "I010") { ui->advancedMsg2->setText( @@ -2612,9 +2617,10 @@ void OBSBasicSettings::UpdateColorFormatSpaceWarning() default: if (format == "NV12") { ui->advancedMsg2->clear(); - } else if ((format == "I010") || (format == "P010")) { + } else if ((format == "I010") || (format == "P010") || + (format == "P216") || (format == "P416")) { ui->advancedMsg2->setText(QTStr( - "Basic.Settings.Advanced.FormatWarning10BitSdr")); + "Basic.Settings.Advanced.FormatWarningPreciseSdr")); } else { ui->advancedMsg2->setText( QTStr("Basic.Settings.Advanced.FormatWarning")); diff --git a/docs/sphinx/reference-libobs-media-io.rst b/docs/sphinx/reference-libobs-media-io.rst index 88ae5c02c..ec88c1658 100644 --- a/docs/sphinx/reference-libobs-media-io.rst +++ b/docs/sphinx/reference-libobs-media-io.rst @@ -48,6 +48,16 @@ Video Handler - VIDEO_FORMAT_I010 - VIDEO_FORMAT_P010 + - VIDEO_FORMAT_I210 + + - VIDEO_FORMAT_I412 + + - VIDEO_FORMAT_YA2L + + - VIDEO_FORMAT_P216 + + - VIDEO_FORMAT_P416 + --------------------- .. enum:: video_trc diff --git a/docs/sphinx/reference-outputs.rst b/docs/sphinx/reference-outputs.rst index 730a6bb4b..28dad3805 100644 --- a/docs/sphinx/reference-outputs.rst +++ b/docs/sphinx/reference-outputs.rst @@ -747,6 +747,21 @@ Functions used by outputs /* planar 4:2:0 format, 10 bpp */ VIDEO_FORMAT_I010, /* three-plane */ VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */ + + /* planar 4:2:2 format, 10 bpp */ + VIDEO_FORMAT_I210, + + /* planar 4:4:4 format, 12 bpp */ + VIDEO_FORMAT_I412, + + /* planar 4:4:4:4 format, 12 bpp */ + VIDEO_FORMAT_YA2L, + + /* planar 4:2:2 format, 16 bpp */ + VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */ + + /* planar 4:4:4 format, 16 bpp */ + VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */ }; enum video_colorspace { diff --git a/docs/sphinx/reference-sources.rst b/docs/sphinx/reference-sources.rst index 6a38adc94..b72e96b45 100644 --- a/docs/sphinx/reference-sources.rst +++ b/docs/sphinx/reference-sources.rst @@ -1425,6 +1425,21 @@ Functions used by sources /* planar 4:2:0 format, 10 bpp */ VIDEO_FORMAT_I010, /* three-plane */ VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */ + + /* planar 4:2:2 format, 10 bpp */ + VIDEO_FORMAT_I210, + + /* planar 4:4:4 format, 12 bpp */ + VIDEO_FORMAT_I412, + + /* planar 4:4:4:4 format, 12 bpp */ + VIDEO_FORMAT_YA2L, + + /* planar 4:2:2 format, 16 bpp */ + VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */ + + /* planar 4:4:4 format, 16 bpp */ + VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */ }; struct obs_source_frame { diff --git a/libobs/data/format_conversion.effect b/libobs/data/format_conversion.effect index 60d8229ae..a88da9eb6 100644 --- a/libobs/data/format_conversion.effect +++ b/libobs/data/format_conversion.effect @@ -252,6 +252,58 @@ float PS_P010_SRGB_Y(FragPos frag_in) : TARGET return y; } +float PS_P216_PQ_Y_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_st2084(rgb); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + +float PS_P216_HLG_Y_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_hlg(rgb, hdr_lw); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + +float PS_P216_SRGB_Y(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; + rgb = srgb_linear_to_nonlinear(rgb); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + +float PS_P416_PQ_Y_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_st2084(rgb); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + +float PS_P416_HLG_Y_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_hlg(rgb, hdr_lw); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + +float PS_P416_SRGB_Y(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; + rgb = srgb_linear_to_nonlinear(rgb); + float y = dot(color_vec0.xyz, rgb) + color_vec0.w; + return y; +} + float PS_I010_PQ_Y_709_2020(FragPos frag_in) : TARGET { float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum; @@ -333,6 +385,76 @@ float2 PS_P010_SRGB_UV_Wide(FragTexWide frag_in) : TARGET return uv; } +float2 PS_P216_PQ_UV_709_2020_Wide(FragTexWide frag_in) : TARGET +{ + float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb; + float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb; + float3 rgb = (rgb_left + rgb_right) * (0.5 * sdr_white_nits_over_maximum); + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_st2084(rgb); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + +float2 PS_P216_HLG_UV_709_2020_Wide(FragTexWide frag_in) : TARGET +{ + float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb; + float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb; + float3 rgb = (rgb_left + rgb_right) * (0.5 * sdr_white_nits_over_maximum); + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_hlg(rgb, hdr_lw); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + +float2 PS_P216_SRGB_UV_Wide(FragTexWide frag_in) : TARGET +{ + float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb; + float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb; + float3 rgb = (rgb_left + rgb_right) * 0.5; + rgb = srgb_linear_to_nonlinear(rgb); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + +float2 PS_P416_PQ_UV_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_st2084(rgb); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + +float2 PS_P416_HLG_UV_709_2020(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; + rgb = rec709_to_rec2020(rgb); + rgb = linear_to_hlg(rgb, hdr_lw); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + +float2 PS_P416_SRGB_UV(FragPos frag_in) : TARGET +{ + float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; + rgb = srgb_linear_to_nonlinear(rgb); + float u = dot(color_vec1.xyz, rgb) + color_vec1.w; + float v = dot(color_vec2.xyz, rgb) + color_vec2.w; + float2 uv = float2(u, v); + return uv; +} + float PS_U(FragPos frag_in) : TARGET { float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb; @@ -1044,6 +1166,114 @@ technique P010_SRGB_UV } } +technique P216_PQ_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P216_PQ_Y_709_2020(frag_in); + } +} + +technique P216_HLG_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P216_HLG_Y_709_2020(frag_in); + } +} + +technique P216_SRGB_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P216_SRGB_Y(frag_in); + } +} + +technique P216_PQ_UV +{ + pass + { + vertex_shader = VSTexPos_Left(id); + pixel_shader = PS_P216_PQ_UV_709_2020_Wide(frag_in); + } +} + +technique P216_HLG_UV +{ + pass + { + vertex_shader = VSTexPos_Left(id); + pixel_shader = PS_P216_HLG_UV_709_2020_Wide(frag_in); + } +} + +technique P216_SRGB_UV +{ + pass + { + vertex_shader = VSTexPos_Left(id); + pixel_shader = PS_P216_SRGB_UV_Wide(frag_in); + } +} + +technique P416_PQ_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_PQ_Y_709_2020(frag_in); + } +} + +technique P416_HLG_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_HLG_Y_709_2020(frag_in); + } +} + +technique P416_SRGB_Y +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_SRGB_Y(frag_in); + } +} + +technique P416_PQ_UV +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_PQ_UV_709_2020(frag_in); + } +} + +technique P416_HLG_UV +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_HLG_UV_709_2020(frag_in); + } +} + +technique P416_SRGB_UV +{ + pass + { + vertex_shader = VSPos(id); + pixel_shader = PS_P416_SRGB_UV(frag_in); + } +} + technique UYVY_Reverse { pass diff --git a/libobs/media-io/video-frame.c b/libobs/media-io/video-frame.c index b5a7e6b95..21491b55e 100644 --- a/libobs/media-io/video-frame.c +++ b/libobs/media-io/video-frame.c @@ -303,6 +303,33 @@ void video_frame_init(struct video_frame *frame, enum video_format format, frame->linesize[1] = cbcr_width * 2; break; } + + case VIDEO_FORMAT_P216: { + size = width * height * 2; + ALIGN_SIZE(size, alignment); + offsets[0] = size; + const uint32_t cbcr_width = (width + 1) & (UINT32_MAX - 1); + size += cbcr_width * height * 2; + ALIGN_SIZE(size, alignment); + frame->data[0] = bmalloc(size); + frame->data[1] = (uint8_t *)frame->data[0] + offsets[0]; + frame->linesize[0] = width * 2; + frame->linesize[1] = cbcr_width * 2; + break; + } + + case VIDEO_FORMAT_P416: { + size = width * height * 2; + ALIGN_SIZE(size, alignment); + offsets[0] = size; + size += width * height * 4; + ALIGN_SIZE(size, alignment); + frame->data[0] = bmalloc(size); + frame->data[1] = (uint8_t *)frame->data[0] + offsets[0]; + frame->linesize[0] = width * 2; + frame->linesize[1] = width * 4; + break; + } } } @@ -362,5 +389,11 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src, memcpy(dst->data[2], src->data[2], src->linesize[2] * cy); memcpy(dst->data[3], src->data[3], src->linesize[3] * cy); break; + + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: + memcpy(dst->data[0], src->data[0], src->linesize[0] * cy); + memcpy(dst->data[1], src->data[1], src->linesize[1] * cy); + break; } } diff --git a/libobs/media-io/video-io.h b/libobs/media-io/video-io.h index 97985a941..b5efc8c70 100644 --- a/libobs/media-io/video-io.h +++ b/libobs/media-io/video-io.h @@ -74,14 +74,20 @@ enum video_format { VIDEO_FORMAT_I010, /* three-plane */ VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */ - /* planar 4:2:2 10 bits */ - VIDEO_FORMAT_I210, // Little Endian + /* planar 4:2:2 format, 10 bpp */ + VIDEO_FORMAT_I210, - /* planar 4:4:4 12 bits */ - VIDEO_FORMAT_I412, // Little Endian + /* planar 4:4:4 format, 12 bpp */ + VIDEO_FORMAT_I412, - /* planar 4:4:4 12 bits with alpha */ - VIDEO_FORMAT_YA2L, // Little Endian + /* planar 4:4:4:4 format, 12 bpp */ + VIDEO_FORMAT_YA2L, + + /* planar 4:2:2 format, 16 bpp */ + VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */ + + /* planar 4:4:4 format, 16 bpp */ + VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */ }; enum video_trc { @@ -145,6 +151,8 @@ static inline bool format_is_yuv(enum video_format format) case VIDEO_FORMAT_AYUV: case VIDEO_FORMAT_I010: case VIDEO_FORMAT_P010: + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: return true; case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_RGBA: @@ -203,6 +211,10 @@ static inline const char *get_video_format_name(enum video_format format) return "I010"; case VIDEO_FORMAT_P010: return "P010"; + case VIDEO_FORMAT_P216: + return "P216"; + case VIDEO_FORMAT_P416: + return "P416"; case VIDEO_FORMAT_NONE:; } diff --git a/libobs/media-io/video-matrices.c b/libobs/media-io/video-matrices.c index a05431305..3feb14673 100644 --- a/libobs/media-io/video-matrices.c +++ b/libobs/media-io/video-matrices.c @@ -269,6 +269,10 @@ bool video_format_get_parameters_for_format(enum video_colorspace color_space, case VIDEO_FORMAT_YA2L: bpc = 12; break; + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: + bpc = 16; + break; default: bpc = 8; break; diff --git a/libobs/media-io/video-scaler-ffmpeg.c b/libobs/media-io/video-scaler-ffmpeg.c index c83fced2e..102ca3d81 100644 --- a/libobs/media-io/video-scaler-ffmpeg.c +++ b/libobs/media-io/video-scaler-ffmpeg.c @@ -68,23 +68,25 @@ get_ffmpeg_video_format(enum video_format format) return AV_PIX_FMT_YUVA422P; case VIDEO_FORMAT_YUVA: return AV_PIX_FMT_YUVA444P; - case VIDEO_FORMAT_YA2L: #if LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 31, 100) + case VIDEO_FORMAT_YA2L: return AV_PIX_FMT_YUVA444P12LE; -#else - return AV_PIX_FMT_NONE; #endif case VIDEO_FORMAT_I010: return AV_PIX_FMT_YUV420P10LE; case VIDEO_FORMAT_P010: return AV_PIX_FMT_P010LE; +#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) + case VIDEO_FORMAT_P216: + return AV_PIX_FMT_P216LE; + case VIDEO_FORMAT_P416: + return AV_PIX_FMT_P416LE; +#endif case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_AYUV: - /* not supported by FFmpeg */ + default: return AV_PIX_FMT_NONE; } - - return AV_PIX_FMT_NONE; } static inline int get_ffmpeg_scale_type(enum video_scale_type type) diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 2ddb6865a..b7df1f235 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -909,6 +909,8 @@ convert_video_format(enum video_format format, enum video_trc trc) case VIDEO_FORMAT_I210: case VIDEO_FORMAT_I412: case VIDEO_FORMAT_YA2L: + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: return GS_RGBA16F; default: return GS_BGRX; diff --git a/libobs/obs-video.c b/libobs/obs-video.c index a2e9653fb..ab66db3c5 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -729,6 +729,33 @@ static void set_gpu_converted_data(struct video_frame *output, break; } + case VIDEO_FORMAT_P216: { + const uint32_t width_x2 = info->width * 2; + const uint32_t height = info->height; + + set_gpu_converted_plane(width_x2, height, input->linesize[0], + output->linesize[0], input->data[0], + output->data[0]); + + set_gpu_converted_plane(width_x2, height, input->linesize[1], + output->linesize[1], input->data[1], + output->data[1]); + + break; + } + case VIDEO_FORMAT_P416: { + const uint32_t height = info->height; + + set_gpu_converted_plane(info->width * 2, height, + input->linesize[0], output->linesize[0], + input->data[0], output->data[0]); + + set_gpu_converted_plane(info->width * 4, height, + input->linesize[1], output->linesize[1], + input->data[1], output->data[1]); + + break; + } case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_YVYU: diff --git a/libobs/obs.c b/libobs/obs.c index db39833ce..bf045f68f 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -109,6 +109,36 @@ static inline void calc_gpu_conversion_sizes(struct obs_core_video_mix *video) video->conversion_techs[1] = "P010_SRGB_UV"; } break; + case VIDEO_FORMAT_P216: + video->conversion_needed = true; + video->conversion_width_i = 1.f / (float)info->width; + video->conversion_height_i = 1.f / (float)info->height; + if (info->colorspace == VIDEO_CS_2100_PQ) { + video->conversion_techs[0] = "P216_PQ_Y"; + video->conversion_techs[1] = "P216_PQ_UV"; + } else if (info->colorspace == VIDEO_CS_2100_HLG) { + video->conversion_techs[0] = "P216_HLG_Y"; + video->conversion_techs[1] = "P216_HLG_UV"; + } else { + video->conversion_techs[0] = "P216_SRGB_Y"; + video->conversion_techs[1] = "P216_SRGB_UV"; + } + break; + case VIDEO_FORMAT_P416: + video->conversion_needed = true; + video->conversion_width_i = 1.f / (float)info->width; + video->conversion_height_i = 1.f / (float)info->height; + if (info->colorspace == VIDEO_CS_2100_PQ) { + video->conversion_techs[0] = "P416_PQ_Y"; + video->conversion_techs[1] = "P416_PQ_UV"; + } else if (info->colorspace == VIDEO_CS_2100_HLG) { + video->conversion_techs[0] = "P416_HLG_Y"; + video->conversion_techs[1] = "P416_HLG_UV"; + } else { + video->conversion_techs[0] = "P416_SRGB_Y"; + video->conversion_techs[1] = "P416_SRGB_UV"; + } + break; default: break; } @@ -237,6 +267,26 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) if (!video->convert_textures[0] || !video->convert_textures[1]) success = false; break; + case VIDEO_FORMAT_P216: + video->convert_textures[0] = + gs_texture_create(info->width, info->height, GS_R16, 1, + NULL, GS_RENDER_TARGET); + video->convert_textures[1] = + gs_texture_create(info->width / 2, info->height, + GS_RG16, 1, NULL, GS_RENDER_TARGET); + if (!video->convert_textures[0] || !video->convert_textures[1]) + success = false; + break; + case VIDEO_FORMAT_P416: + video->convert_textures[0] = + gs_texture_create(info->width, info->height, GS_R16, 1, + NULL, GS_RENDER_TARGET); + video->convert_textures[1] = + gs_texture_create(info->width, info->height, GS_RG16, 1, + NULL, GS_RENDER_TARGET); + if (!video->convert_textures[0] || !video->convert_textures[1]) + success = false; + break; default: break; } @@ -328,6 +378,26 @@ static bool obs_init_gpu_copy_surfaces(struct obs_core_video_mix *video, if (!video->copy_surfaces[i][1]) return false; break; + case VIDEO_FORMAT_P216: + video->copy_surfaces[i][0] = gs_stagesurface_create( + info->width, info->height, GS_R16); + if (!video->copy_surfaces[i][0]) + return false; + video->copy_surfaces[i][1] = gs_stagesurface_create( + info->width / 2, info->height, GS_RG16); + if (!video->copy_surfaces[i][1]) + return false; + break; + case VIDEO_FORMAT_P416: + video->copy_surfaces[i][0] = gs_stagesurface_create( + info->width, info->height, GS_R16); + if (!video->copy_surfaces[i][0]) + return false; + video->copy_surfaces[i][1] = gs_stagesurface_create( + info->width, info->height, GS_RG16); + if (!video->copy_surfaces[i][1]) + return false; + break; default: break; } @@ -349,6 +419,8 @@ static bool obs_init_textures(struct obs_core_video_mix *video) case VIDEO_FORMAT_I210: case VIDEO_FORMAT_I412: case VIDEO_FORMAT_YA2L: + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: format = GS_RGBA16F; break; default: @@ -398,9 +470,17 @@ static bool obs_init_textures(struct obs_core_video_mix *video) space = GS_CS_709_EXTENDED; break; default: - if (info->format == VIDEO_FORMAT_I010 || - info->format == VIDEO_FORMAT_P010) + switch (info->format) { + case VIDEO_FORMAT_I010: + case VIDEO_FORMAT_P010: + case VIDEO_FORMAT_P216: + case VIDEO_FORMAT_P416: space = GS_CS_SRGB_16F; + break; + default: + space = GS_CS_SRGB; + break; + } break; } diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-formats.h b/plugins/obs-ffmpeg/obs-ffmpeg-formats.h index c33424a24..b9cc7ac5d 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-formats.h +++ b/plugins/obs-ffmpeg/obs-ffmpeg-formats.h @@ -56,6 +56,12 @@ obs_to_ffmpeg_video_format(enum video_format format) return AV_PIX_FMT_YUV420P10LE; case VIDEO_FORMAT_P010: return AV_PIX_FMT_P010LE; +#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) + case VIDEO_FORMAT_P216: + return AV_PIX_FMT_P216LE; + case VIDEO_FORMAT_P416: + return AV_PIX_FMT_P416LE; +#endif case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_AYUV: default: