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
{
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"
" 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"
" 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 */
" 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[] =
typedef struct
{
const PixelShaderTemplate *templ;
- gchar *ps_body;
+ gchar *ps_body[CONVERTER_MAX_QUADS];
PixelShaderColorTransform transform;
} ConvertInfo;
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;
};
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;
}
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,
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
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, };
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;
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);
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, };
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
ID3D11DeviceContext_Unmap (context_handle,
(ID3D11Resource *) vertex_buffer, 0);
gst_d3d11_device_unlock (device);
- data->ret = FALSE;
+ ret = FALSE;
goto clear;
}
(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)
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);
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;
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);
}
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
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;
}