From a122f305f91e8b1db8fb9041767f9292dfd7e9c3 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Wed, 8 Jan 2020 23:09:51 +0900 Subject: [PATCH] d3d11colorconverter: Add support for RGB to YUV conversion ... and remove code for RGBx since it's not supported format by our d3d11 implementation for now. --- sys/d3d11/gstd3d11colorconverter.c | 316 +++++++++++++++++++++++-------------- 1 file changed, 200 insertions(+), 116 deletions(-) diff --git a/sys/d3d11/gstd3d11colorconverter.c b/sys/d3d11/gstd3d11colorconverter.c index 783e772..7f8b4a6 100644 --- a/sys/d3d11/gstd3d11colorconverter.c +++ b/sys/d3d11/gstd3d11colorconverter.c @@ -33,6 +33,8 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_colorconverter_debug); #define GST_CAT_DEFAULT gst_d3d11_colorconverter_debug +#define CONVERTER_MAX_QUADS 2 + /* *INDENT-OFF* */ typedef struct { @@ -89,17 +91,11 @@ static const PixelShaderTemplate templ_REORDER = static const PixelShaderTemplate templ_YUV_to_RGB = { COLOR_TRANSFORM_COEFF, HLSL_FUNC_YUV_TO_RGB }; -#if 0 static const PixelShaderTemplate templ_RGB_to_YUV = { COLOR_TRANSFORM_COEFF, HLSL_FUNC_RGB_TO_YUV }; -#endif static const gchar templ_REORDER_BODY[] = - " float4 sample;\n" - " sample = shaderTexture[0].Sample(samplerState, input.Texture);\n" - /* alpha channel */ - " %s\n" - " return sample;\n"; + " output.Plane_0 = shaderTexture[0].Sample(samplerState, input.Texture);\n"; static const gchar templ_VUYA_to_RGB_BODY[] = " float4 sample, rgba;\n" @@ -109,37 +105,24 @@ static const gchar templ_VUYA_to_RGB_BODY[] = " sample.a = shaderTexture[0].Sample(samplerState, input.Texture).a;\n" " rgba.rgb = yuv_to_rgb (sample.xyz);\n" " rgba.a = sample.a;\n" - " return rgba;\n"; + " output.Plane_0 = rgba;\n"; -#if 0 static const gchar templ_RGB_to_VUYA_BODY[] = " float4 sample, vuya;\n" " sample = shaderTexture[0].Sample(samplerState, input.Texture);\n" " vuya.zyx = rgb_to_yuv (sample.rgb);\n" - " vuya.a = %s;\n" - " return vuya;\n"; -#endif + " vuya.a = sample.a;\n" + " output.Plane_0 = vuya;\n"; /* YUV to RGB conversion */ static const gchar templ_PLANAR_YUV_to_RGB_BODY[] = " float4 sample, rgba;\n" - " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n" - " sample.y = shaderTexture[1].Sample(samplerState, input.Texture).x;\n" - " sample.z = shaderTexture[2].Sample(samplerState, input.Texture).x;\n" - " rgba.rgb = yuv_to_rgb (sample.xyz);\n" - " rgba.a = 1.0;\n" - " return rgba;\n"; - -static const gchar templ_PLANAR_YUV_HIGH_to_RGB_BODY[] = - " float4 sample, rgba;\n" " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %d;\n" " sample.y = shaderTexture[1].Sample(samplerState, input.Texture).x * %d;\n" " sample.z = shaderTexture[2].Sample(samplerState, input.Texture).x * %d;\n" " rgba.rgb = yuv_to_rgb (sample.xyz);\n" " rgba.a = 1.0;\n" - " return rgba;\n"; - -/* FIXME: add RGB to planar */ + " output.Plane_0 = rgba;\n"; static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] = " float4 sample, rgba;\n" @@ -147,9 +130,35 @@ static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] = " sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).xy;\n" " rgba.rgb = yuv_to_rgb (sample.xyz);\n" " rgba.a = 1.0;\n" - " return rgba;\n"; + " output.Plane_0 = rgba;\n"; -/* FIXME: add RGB to semi-planar */ +/* RGB to YUV conversion */ +static const gchar templ_RGB_to_LUMA_BODY[] = + " float4 sample, rgba;\n" + " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n" + " sample.xyz = rgb_to_yuv (rgba.rgb);\n" + " sample.y = 0.0;\n" + " sample.z = 0.0;\n" + " sample.a = 0.0;\n" + " sample.x = sample.x / %d;\n" + " output.Plane_0 = sample;\n"; + +static const gchar templ_RGB_to_SEMI_PLANAR_CHROMA_BODY[] = + " float4 sample, rgba;\n" + " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n" + " sample.xyz = rgb_to_yuv (rgba.rgb);\n" + " sample.x = sample.y;\n" + " sample.y = sample.z;\n" + " sample.z = 0.0;\n" + " sample.a = 0.0;\n" + " output.Plane_0 = sample;\n"; + +static const gchar templ_RGB_to_PLANAR_CHROMA_BODY[] = + " float4 sample, rgba;\n" + " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n" + " sample.xyz = rgb_to_yuv (rgba.rgb);\n" + " output.Plane_0 = float4(sample.y / %d, 0.0, 0.0, 0.0);\n" + " output.Plane_1 = float4(sample.z / %d, 0.0, 0.0, 0.0);\n"; static const gchar templ_pixel_shader[] = /* constant buffer */ @@ -163,11 +172,19 @@ static const gchar templ_pixel_shader[] = " float3 Texture: TEXCOORD0;\n" "};\n" "\n" + "struct PS_OUTPUT\n" + "{\n" + " float4 Plane_0: SV_TARGET0;\n" + " float4 Plane_1: SV_TARGET1;\n" + "};\n" + "\n" /* rgb <-> yuv function */ "%s\n" - "float4 main(PS_INPUT input): SV_TARGET\n" + "PS_OUTPUT main(PS_INPUT input)\n" "{\n" + " PS_OUTPUT output;\n" "%s" + " return output;\n" "}\n"; static const gchar templ_vertex_shader[] = @@ -193,7 +210,7 @@ static const gchar templ_vertex_shader[] = typedef struct { const PixelShaderTemplate *templ; - gchar *ps_body; + gchar *ps_body[CONVERTER_MAX_QUADS]; PixelShaderColorTransform transform; } ConvertInfo; @@ -209,9 +226,9 @@ struct _GstD3D11ColorConverter guint num_input_view; guint num_output_view; - GstD3D11Quad *quad; + GstD3D11Quad *quad[CONVERTER_MAX_QUADS]; - D3D11_VIEWPORT viewport; + D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES]; ConvertInfo convert_info; }; @@ -453,19 +470,9 @@ setup_convert_info_rgb_to_rgb (GstD3D11ColorConverter * self, const GstVideoInfo * in_info, const GstVideoInfo * out_info) { ConvertInfo *convert_info = &self->convert_info; - GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (in_info); - -#define IS_RGBX_FORMAT(f) \ - ((f) == GST_VIDEO_FORMAT_RGBx || \ - (f) == GST_VIDEO_FORMAT_xRGB || \ - (f) == GST_VIDEO_FORMAT_BGRx || \ - (f) == GST_VIDEO_FORMAT_xBGR) convert_info->templ = &templ_REORDER; - convert_info->ps_body = g_strdup_printf (templ_REORDER_BODY, - IS_RGBX_FORMAT (in_format) ? "sample.a = 1.0f;" : ""); - -#undef IS_RGBX_FORMAT + convert_info->ps_body[0] = g_strdup_printf (templ_REORDER_BODY); return TRUE; } @@ -480,18 +487,19 @@ setup_convert_info_yuv_to_rgb (GstD3D11ColorConverter * self, switch (GST_VIDEO_INFO_FORMAT (in_info)) { case GST_VIDEO_FORMAT_VUYA: - info->ps_body = g_strdup_printf (templ_VUYA_to_RGB_BODY); + info->ps_body[0] = g_strdup_printf (templ_VUYA_to_RGB_BODY); break; case GST_VIDEO_FORMAT_I420: - info->ps_body = g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY); + info->ps_body[0] = + g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, 1, 1, 1); break; case GST_VIDEO_FORMAT_I420_10LE: - info->ps_body = - g_strdup_printf (templ_PLANAR_YUV_HIGH_to_RGB_BODY, 64, 64, 64); + info->ps_body[0] = + g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, 64, 64, 64); break; case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_P010_10LE: - info->ps_body = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY); + info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY); break; default: GST_FIXME_OBJECT (self, @@ -507,8 +515,37 @@ static gboolean setup_convert_info_rgb_to_yuv (GstD3D11ColorConverter * self, const GstVideoInfo * in_info, const GstVideoInfo * out_info) { - GST_FIXME ("Implement RGB to YUV format conversion"); - return FALSE; + ConvertInfo *info = &self->convert_info; + + info->templ = &templ_RGB_to_YUV; + + switch (GST_VIDEO_INFO_FORMAT (out_info)) { + case GST_VIDEO_FORMAT_VUYA: + info->ps_body[0] = g_strdup_printf (templ_RGB_to_VUYA_BODY); + break; + case GST_VIDEO_FORMAT_NV12: + case GST_VIDEO_FORMAT_P010_10LE: + info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 1); + info->ps_body[1] = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_CHROMA_BODY); + break; + case GST_VIDEO_FORMAT_I420: + info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 1); + info->ps_body[1] = + g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, 1, 1); + break; + case GST_VIDEO_FORMAT_I420_10LE: + info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 64); + info->ps_body[1] = + g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, 64, 64); + break; + default: + GST_FIXME_OBJECT (self, + "Unhandled output format %s", + gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info))); + return FALSE; + } + + return TRUE; } static gboolean @@ -519,19 +556,10 @@ setup_convert_info_yuv_to_yuv (GstD3D11ColorConverter * self, return FALSE; } -typedef struct -{ - GstD3D11ColorConverter *self; - GstVideoInfo *in_info; - GstVideoInfo *out_info; - gboolean ret; -} SetupShaderData; - -static void -gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, - SetupShaderData * data) +static gboolean +gst_d3d11_color_convert_setup_shader (GstD3D11ColorConverter * self, + GstD3D11Device * device, GstVideoInfo * in_info, GstVideoInfo * out_info) { - GstD3D11ColorConverter *self = data->self; HRESULT hr; D3D11_SAMPLER_DESC sampler_desc = { 0, }; D3D11_INPUT_ELEMENT_DESC input_desc[2] = { 0, }; @@ -541,9 +569,8 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, WORD *indices; ID3D11Device *device_handle; ID3D11DeviceContext *context_handle; - gchar *shader_code = NULL; ConvertInfo *convert_info = &self->convert_info; - ID3D11PixelShader *ps = NULL; + ID3D11PixelShader *ps[CONVERTER_MAX_QUADS] = { NULL, NULL }; ID3D11VertexShader *vs = NULL; ID3D11InputLayout *layout = NULL; ID3D11SamplerState *sampler = NULL; @@ -551,8 +578,8 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, ID3D11Buffer *vertex_buffer = NULL; ID3D11Buffer *index_buffer = NULL; const guint index_count = 2 * 3; - - data->ret = TRUE; + gboolean ret = TRUE; + gint i; device_handle = gst_d3d11_device_get_device_handle (device); context_handle = gst_d3d11_device_get_device_context_handle (device); @@ -569,28 +596,29 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, hr = ID3D11Device_CreateSamplerState (device_handle, &sampler_desc, &sampler); if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't create sampler state, hr: 0x%x", (guint) hr); - data->ret = FALSE; + ret = FALSE; goto clear; } - shader_code = g_strdup_printf (templ_pixel_shader, - convert_info->templ->constant_buffer ? - convert_info->templ->constant_buffer : "", - convert_info->templ->func ? convert_info->templ->func : "", - convert_info->ps_body); - - GST_LOG ("Create Pixel Shader \n%s", shader_code); - - if (!gst_d3d11_create_pixel_shader (device, shader_code, &ps)) { - GST_ERROR ("Couldn't create pixel shader"); - - g_free (shader_code); - data->ret = FALSE; - goto clear; + for (i = 0; i < CONVERTER_MAX_QUADS; i++) { + gchar *shader_code = NULL; + + if (convert_info->ps_body[i]) { + shader_code = g_strdup_printf (templ_pixel_shader, + convert_info->templ->constant_buffer ? + convert_info->templ->constant_buffer : "", + convert_info->templ->func ? convert_info->templ->func : "", + convert_info->ps_body[i]); + + ret = gst_d3d11_create_pixel_shader (device, shader_code, &ps[i]); + g_free (shader_code); + if (!ret) { + GST_ERROR ("Couldn't create pixel shader"); + goto clear; + } + } } - g_free (shader_code); - if (convert_info->templ->constant_buffer) { D3D11_BUFFER_DESC const_buffer_desc = { 0, }; @@ -606,7 +634,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't create constant buffer, hr: 0x%x", (guint) hr); - data->ret = FALSE; + ret = FALSE; goto clear; } @@ -616,8 +644,8 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr); - data->ret = FALSE; gst_d3d11_device_unlock (device); + ret = FALSE; goto clear; } @@ -648,7 +676,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_create_vertex_shader (device, templ_vertex_shader, input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) { GST_ERROR ("Couldn't vertex pixel shader"); - data->ret = FALSE; + ret = FALSE; goto clear; } @@ -663,7 +691,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't create vertex buffer, hr: 0x%x", (guint) hr); - data->ret = FALSE; + ret = FALSE; goto clear; } @@ -677,7 +705,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr); - data->ret = FALSE; + ret = FALSE; goto clear; } @@ -687,8 +715,8 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr); - data->ret = FALSE; gst_d3d11_device_unlock (device); + ret = FALSE; goto clear; } @@ -702,7 +730,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, ID3D11DeviceContext_Unmap (context_handle, (ID3D11Resource *) vertex_buffer, 0); gst_d3d11_device_unlock (device); - data->ret = FALSE; + ret = FALSE; goto clear; } @@ -751,16 +779,24 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device, (ID3D11Resource *) index_buffer, 0); gst_d3d11_device_unlock (device); - self->quad = gst_d3d11_quad_new (device, - ps, vs, layout, sampler, NULL, NULL, const_buffer, vertex_buffer, + self->quad[0] = gst_d3d11_quad_new (device, + ps[0], vs, layout, sampler, NULL, NULL, const_buffer, vertex_buffer, sizeof (VertexData), index_buffer, DXGI_FORMAT_R16_UINT, index_count); - self->num_input_view = GST_VIDEO_INFO_N_PLANES (data->in_info); - self->num_output_view = GST_VIDEO_INFO_N_PLANES (data->out_info); + if (ps[1]) { + self->quad[1] = gst_d3d11_quad_new (device, + ps[1], vs, layout, sampler, NULL, NULL, const_buffer, vertex_buffer, + sizeof (VertexData), index_buffer, DXGI_FORMAT_R16_UINT, index_count); + } + + self->num_input_view = GST_VIDEO_INFO_N_PLANES (in_info); + self->num_output_view = GST_VIDEO_INFO_N_PLANES (out_info); clear: - if (ps) - ID3D11PixelShader_Release (ps); + for (i = 0; i < CONVERTER_MAX_QUADS; i++) { + if (ps[i]) + ID3D11PixelShader_Release (ps[i]); + } if (vs) ID3D11VertexShader_Release (vs); if (layout) @@ -774,20 +810,21 @@ clear: if (index_buffer) ID3D11Buffer_Release (index_buffer); - return; + return ret; } GstD3D11ColorConverter * gst_d3d11_color_converter_new (GstD3D11Device * device, GstVideoInfo * in_info, GstVideoInfo * out_info) { - SetupShaderData data; const GstVideoInfo *unknown_info; const GstD3D11Format *in_d3d11_format; const GstD3D11Format *out_d3d11_format; gboolean is_supported = FALSE; MatrixData matrix; GstD3D11ColorConverter *converter = NULL; + gboolean ret; + gint i; g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL); g_return_val_if_fail (in_info != NULL, NULL); @@ -853,22 +890,25 @@ gst_d3d11_color_converter_new (GstD3D11Device * device, transform->trans_matrix[11] = 0; } - converter->viewport.TopLeftX = 0; - converter->viewport.TopLeftY = 0; - converter->viewport.Width = GST_VIDEO_INFO_WIDTH (out_info); - converter->viewport.Height = GST_VIDEO_INFO_HEIGHT (out_info); - converter->viewport.MinDepth = 0.0f; - converter->viewport.MaxDepth = 1.0f; + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (out_info); i++) { + converter->viewport[i].TopLeftX = 0; + converter->viewport[i].TopLeftY = 0; + converter->viewport[i].Width = GST_VIDEO_INFO_COMP_WIDTH (out_info, i); + converter->viewport[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (out_info, i); + converter->viewport[i].MinDepth = 0.0f; + converter->viewport[i].MaxDepth = 1.0f; + } - data.self = converter; - data.in_info = in_info; - data.out_info = out_info; - gst_d3d11_color_convert_setup_shader (device, &data); + ret = gst_d3d11_color_convert_setup_shader (converter, + device, in_info, out_info); - if (!data.ret || !converter->quad) { + if (!ret) { GST_ERROR ("Couldn't setup shader"); gst_d3d11_color_converter_free (converter); converter = NULL; + } else { + converter->in_info = *in_info; + converter->out_info = *out_info; } return converter; @@ -893,13 +933,18 @@ conversion_not_supported: void gst_d3d11_color_converter_free (GstD3D11ColorConverter * converter) { + gint i; + g_return_if_fail (converter != NULL); - if (converter->quad) - gst_d3d11_quad_free (converter->quad); + for (i = 0; i < CONVERTER_MAX_QUADS; i++) { + if (converter->quad[i]) + gst_d3d11_quad_free (converter->quad[i]); + + g_free (converter->convert_info.ps_body[i]); + } gst_clear_object (&converter->device); - g_free (converter->convert_info.ps_body); g_free (converter); } @@ -926,12 +971,29 @@ gst_d3d11_color_converter_convert_unlocked (GstD3D11ColorConverter * converter, ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES], ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES]) { + gboolean ret; + g_return_val_if_fail (converter != NULL, FALSE); g_return_val_if_fail (srv != NULL, FALSE); g_return_val_if_fail (rtv != NULL, FALSE); - return gst_d3d11_draw_quad_unlocked (converter->quad, &converter->viewport, 1, - srv, converter->num_input_view, rtv, converter->num_output_view, NULL); + ret = gst_d3d11_draw_quad_unlocked (converter->quad[0], converter->viewport, + 1, srv, converter->num_input_view, rtv, 1, NULL); + + if (!ret) + return FALSE; + + if (converter->quad[1]) { + ret = gst_d3d11_draw_quad_unlocked (converter->quad[1], + &converter->viewport[1], converter->num_output_view - 1, + srv, converter->num_input_view, &rtv[1], converter->num_output_view - 1, + NULL); + + if (!ret) + return FALSE; + } + + return TRUE; } gboolean @@ -941,10 +1003,32 @@ gst_d3d11_color_converter_update_rect (GstD3D11ColorConverter * converter, g_return_val_if_fail (converter != NULL, FALSE); g_return_val_if_fail (rect != NULL, FALSE); - converter->viewport.TopLeftX = rect->left; - converter->viewport.TopLeftY = rect->top; - converter->viewport.Width = rect->right - rect->left; - converter->viewport.Height = rect->bottom - rect->top; + converter->viewport[0].TopLeftX = rect->left; + converter->viewport[0].TopLeftY = rect->top; + converter->viewport[0].Width = rect->right - rect->left; + converter->viewport[0].Height = rect->bottom - rect->top; + + switch (GST_VIDEO_INFO_FORMAT (&converter->out_info)) { + case GST_VIDEO_FORMAT_NV12: + case GST_VIDEO_FORMAT_P010_10LE: + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_I420_10LE:{ + gint i; + converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2; + converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY / 2; + converter->viewport[1].Width = converter->viewport[0].Width / 2; + converter->viewport[1].Height = converter->viewport[0].Height / 2; + + for (i = 2; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++) + converter->viewport[i] = converter->viewport[1]; + + break; + } + default: + if (converter->num_output_view > 1) + g_assert_not_reached (); + break; + } return TRUE; } -- 2.7.4