d3d11: Add support for YV12 and NV21 formats
authorSeungha Yang <seungha@centricular.com>
Fri, 28 May 2021 16:48:15 +0000 (01:48 +0900)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 3 Jun 2021 17:00:49 +0000 (17:00 +0000)
Handle UV swapped 4:2:0 8bits formats

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2290>

gst-libs/gst/d3d11/gstd3d11device.c
gst-libs/gst/d3d11/gstd3d11format.h
sys/d3d11/gstd3d11converter.cpp
tests/check/elements/d3d11colorconvert.c

index b866287..526836f 100644 (file)
@@ -90,6 +90,8 @@ enum
 #define DEFAULT_ADAPTER 0
 #define DEFAULT_CREATE_FLAGS 0
 
+#define GST_D3D11_N_FORMATS 18
+
 struct _GstD3D11DevicePrivate
 {
   guint adapter;
@@ -590,6 +592,13 @@ gst_d3d11_device_setup_format_table (GstD3D11Device * self)
     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
   n_formats++;
 
+  /* no native format for NV21 */
+  priv->format_table[n_formats].format = GST_VIDEO_FORMAT_NV21;
+  priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
+  priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
+  priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
+  n_formats++;
+
   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P010_10LE;
   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
@@ -619,6 +628,12 @@ gst_d3d11_device_setup_format_table (GstD3D11Device * self)
   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
   n_formats++;
 
+  priv->format_table[n_formats].format = GST_VIDEO_FORMAT_YV12;
+  priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
+  priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
+  priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
+  n_formats++;
+
   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420_10LE;
   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
index 1ac521e..fb2980d 100644 (file)
@@ -27,7 +27,8 @@
 G_BEGIN_DECLS
 
 #define GST_D3D11_COMMON_FORMATS \
-    "BGRA, RGBA, RGB10A2_LE, BGRx, RGBx, VUYA, NV12, P010_10LE, P016_LE, I420, I420_10LE"
+    "BGRA, RGBA, RGB10A2_LE, BGRx, RGBx, VUYA, NV12, NV21, " \
+    "P010_10LE, P016_LE, I420, YV12, I420_10LE"
 
 #define GST_D3D11_EXTRA_IN_FORMATS \
     "YUY2, UYVY, VYUY, Y210, Y410"
@@ -41,8 +42,6 @@ G_BEGIN_DECLS
 #define GST_D3D11_ALL_FORMATS \
     "{ " GST_D3D11_COMMON_FORMATS " ," GST_D3D11_EXTRA_IN_FORMATS " }"
 
-#define GST_D3D11_N_FORMATS 16
-
 struct _GstD3D11Format
 {
   GstVideoFormat format;
index 09ccba8..0206080 100644 (file)
@@ -156,9 +156,9 @@ static const gchar templ_PACKED_YUV_to_RGB_BODY[] =
 /* 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 * %d;\n"
-    "  sample.y  = shaderTexture[1].Sample(samplerState, input.Texture).x * %d;\n"
-    "  sample.z  = shaderTexture[2].Sample(samplerState, input.Texture).x * %d;\n"
+    "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
+    "  sample.%c  = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
+    "  sample.%c  = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
     "  rgba.a = 1.0;\n"
     "  output.Plane_0 = rgba;\n";
@@ -166,7 +166,7 @@ static const gchar templ_PLANAR_YUV_to_RGB_BODY[] =
 static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] =
     "  float4 sample, rgba;\n"
     "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
-    "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).xy;\n"
+    "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
     "  rgba.a = 1.0;\n"
     "  output.Plane_0 = rgba;\n";
@@ -186,8 +186,8 @@ 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.%c = sample.y;\n"
+    "  sample.%c = sample.z;\n"
     "  sample.z = 0.0;\n"
     "  sample.a = 0.0;\n"
     "  output.Plane_0 = sample;\n";
@@ -196,68 +196,70 @@ 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";
+    "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
+    "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
 
 /* YUV to YUV conversion */
 static const gchar templ_LUMA_to_LUMA_BODY[] =
     "  float4 sample;\n"
-    "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %d;\n"
-    "  output.Plane_0 = float4(sample.x / %d, 0.0, 0.0, 0.0);\n";
+    "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
+    "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
-    "  float4 sample;\n"
-    "  sample.y = shaderTexture[1].Sample(samplerState, input.Texture).x * %d;\n"
-    "  sample.z = shaderTexture[2].Sample(samplerState, input.Texture).x * %d;\n"
-    "  output.Plane_0 = float4(sample.yz, 0.0, 0.0);\n";
+    "  float4 in_sample;\n"
+    "  float4 out_sample;\n"
+    "  in_sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
+    "  in_sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
+    "  out_sample.xy = in_sample.yz;\n"
+    "  output.Plane_0 = float4(out_sample.%c%c, 0.0, 0.0);\n";
 
 static const gchar templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
-    "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).xy;\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";
+    "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
+    "  output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
+    "  output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
-    "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).xy;\n"
-    "  output.Plane_0 = float4(sample.yz, 0.0, 0.0);\n";
+    "  sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
+    "  output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
 
 static const gchar templ_PLANAR_TO_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
-    "  sample.y = shaderTexture[1].Sample(samplerState, input.Texture).x * %d;\n"
-    "  sample.z = shaderTexture[2].Sample(samplerState, input.Texture).x * %d;\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";
+    "  sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
+    "  sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
+    "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
+    "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
 
 /* VUYA to YUV */
 static const gchar templ_VUYA_to_LUMA_BODY[] =
     "  float4 sample;\n"
     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
-    "  output.Plane_0 = float4(sample.x / %d, 0.0, 0.0, 0.0);\n";
+    "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_VUYA_TO_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
     "  sample.yz = shaderTexture[0].Sample(samplerState, input.Texture).yx;\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";
+    "  output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
+    "  output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY[] =
-    "  float4 sample;\n"
-    "  sample.yz = shaderTexture[0].Sample(samplerState, input.Texture).yx;\n"
-    "  output.Plane_0 = float4(sample.yz, 0.0, 0.0);\n";
+    "  float2 sample;\n"
+    "  sample.xy = shaderTexture[0].Sample(samplerState, input.Texture).%c%c;\n"
+    "  output.Plane_0 = float4(sample.xy, 0.0, 0.0);\n";
 
 /* YUV to VUYA */
 static const gchar templ_PLANAR_to_VUYA_BODY[] =
     "  float4 sample;\n"
-    "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x * %d;\n"
-    "  sample.y = shaderTexture[1].Sample(samplerState, input.Texture).x * %d;\n"
-    "  sample.x = shaderTexture[2].Sample(samplerState, input.Texture).x * %d;\n"
-    "  output.Plane_0 = float4(sample.xyz, 1.0f);\n";
+    "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
+    "  sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
+    "  sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
+    "  output.Plane_0 = float4(sample.zyx, 1.0f);\n";
 
 static const gchar templ_SEMI_PLANAR_to_VUYA_BODY[] =
     "  float4 sample;\n"
     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
-    "  sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).yx;\n"
+    "  sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
     "  output.Plane_0 = float4(sample.xyz, 1.0f);\n";
 
 static const gchar templ_PACKED_YUV_to_VUYA_BODY[] =
@@ -271,20 +273,20 @@ static const gchar templ_PACKED_YUV_to_VUYA_BODY[] =
 static const gchar templ_PACKED_YUV_to_LUMA_BODY[] =
     "  float4 sample;\n"
     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
-    "  output.Plane_0 = float4(sample.x / %d, 0.0, 0.0, 0.0);\n";
+    "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
     "  sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\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";
+    "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
+    "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
 
 static const gchar templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY[] =
     "  float4 sample;\n"
+    "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
     "  sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
-    "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
-    "  output.Plane_0 = float4(sample.yz, 0.0, 0.0);\n";
+    "  output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
 
 static const gchar templ_pixel_shader[] =
     /* constant buffer */
@@ -690,6 +692,36 @@ get_packed_yuv_components (GstD3D11Converter * self, GstVideoFormat
   return TRUE;
 }
 
+static void
+get_planar_component (const GstVideoInfo * info, gchar * u, gchar * v,
+    guint * scale)
+{
+  if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_I420_10LE)
+    *scale = 64;
+  else
+    *scale = 1;
+
+  if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_YV12) {
+    *u = 'z';
+    *v = 'y';
+  } else {
+    *u = 'y';
+    *v = 'z';
+  }
+}
+
+static void
+get_semi_planar_component (const GstVideoInfo * info, gchar * u, gchar * v)
+{
+  if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_NV21) {
+    *u = 'y';
+    *v = 'x';
+  } else {
+    *u = 'x';
+    *v = 'y';
+  }
+}
+
 static gboolean
 setup_convert_info_yuv_to_rgb (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
@@ -720,18 +752,30 @@ setup_convert_info_yuv_to_rgb (GstD3D11Converter * self,
       break;
     }
     case GST_VIDEO_FORMAT_I420:
-      info->ps_body[0] =
-          g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, 1, 1, 1);
-      break;
+    case GST_VIDEO_FORMAT_YV12:
     case GST_VIDEO_FORMAT_I420_10LE:
+    {
+      guint mul;
+      gchar u, v;
+
+      get_planar_component (in_info, &u, &v, &mul);
+
       info->ps_body[0] =
-          g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, 64, 64, 64);
+          g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, mul, u, mul, v, mul);
       break;
+    }
     case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
     case GST_VIDEO_FORMAT_P010_10LE:
     case GST_VIDEO_FORMAT_P016_LE:
-      info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY);
+    {
+      gchar u, v;
+
+      get_semi_planar_component (in_info, &u, &v);
+
+      info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, u, v);
       break;
+    }
     default:
       GST_FIXME_OBJECT (self,
           "Unhandled input format %s",
@@ -756,24 +800,35 @@ setup_convert_info_rgb_to_yuv (GstD3D11Converter * self,
       info->ps_body[0] = g_strdup_printf (templ_RGB_to_VUYA_BODY);
       break;
     case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
     case GST_VIDEO_FORMAT_P010_10LE:
     case GST_VIDEO_FORMAT_P016_LE:
+    {
+      gchar u, v;
+
+      get_semi_planar_component (out_info, &u, &v);
+
       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);
+      info->ps_body[1] = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_CHROMA_BODY,
+          u, v);
       info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_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);
-      info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
-      break;
+    case GST_VIDEO_FORMAT_YV12:
     case GST_VIDEO_FORMAT_I420_10LE:
-      info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 64);
+    {
+      guint div;
+      gchar u, v;
+
+      get_planar_component (out_info, &u, &v, &div);
+
+      info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, div);
       info->ps_body[1] =
-          g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, 64, 64);
+          g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, u, div, v, div);
       info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
       break;
+    }
     default:
       GST_FIXME_OBJECT (self,
           "Unhandled output format %s",
@@ -789,22 +844,21 @@ setup_convert_info_planar_to_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint mul = 1;
-  gint div = 1;
+  guint in_scale, out_scale;
+  gchar in_u, in_v, out_u, out_v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_I420_10LE)
-    mul = 64;
-
-  if (GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420_10LE)
-    div = 64;
+  get_planar_component (in_info, &in_u, &in_v, &in_scale);
+  get_planar_component (out_info, &out_u, &out_v, &out_scale);
 
-  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, mul, div);
+  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY,
+      in_scale, out_scale);
   info->ps_body[1] =
-      g_strdup_printf (templ_PLANAR_TO_PLANAR_CHROMA_BODY, mul, mul, div, div);
+      g_strdup_printf (templ_PLANAR_TO_PLANAR_CHROMA_BODY,
+      in_u, in_scale, in_v, in_scale, out_u, out_scale, out_v, out_scale);
 
   return TRUE;
 }
@@ -814,19 +868,20 @@ setup_convert_info_planar_to_semi_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint mul = 1;
-  gint div = 1;
+  guint in_scale;
+  gchar in_u, in_v, out_u, out_v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_I420_10LE)
-    mul = 64;
+  get_planar_component (in_info, &in_u, &in_v, &in_scale);
+  get_semi_planar_component (out_info, &out_u, &out_v);
 
-  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, mul, div);
+  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, in_scale, 1);
   info->ps_body[1] =
-      g_strdup_printf (templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY, mul, mul);
+      g_strdup_printf (templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
+      in_u, in_scale, in_v, in_scale, out_u, out_v);
 
   return TRUE;
 }
@@ -836,19 +891,20 @@ setup_convert_info_semi_planar_to_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint mul = 1;
-  gint div = 1;
+  gchar in_u, in_v, out_u, out_v;
+  guint div = 1;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420_10LE)
-    div = 64;
+  get_semi_planar_component (in_info, &in_u, &in_v);
+  get_planar_component (out_info, &out_u, &out_v, &div);
 
-  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, mul, div);
+  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, div);
   info->ps_body[1] =
-      g_strdup_printf (templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY, div, div);
+      g_strdup_printf (templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY,
+      in_u, in_v, out_u, div, out_v, div);
 
   return TRUE;
 }
@@ -858,16 +914,19 @@ setup_convert_info_semi_planar_to_semi_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint mul = 1;
-  gint div = 1;
+  gchar in_u, in_v, out_u, out_v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
-  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, mul, div);
+  get_semi_planar_component (in_info, &in_u, &in_v);
+  get_semi_planar_component (out_info, &out_u, &out_v);
+
+  info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, 1);
   info->ps_body[1] =
-      g_strdup_printf (templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY);
+      g_strdup_printf (templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
+      in_u, in_v, out_u, out_v);
 
   return TRUE;
 }
@@ -891,18 +950,18 @@ setup_convert_info_vuya_to_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint div = 1;
+  guint div;
+  gchar u, v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420_10LE)
-    div = 64;
+  get_planar_component (out_info, &u, &v, &div);
 
   info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
   info->ps_body[1] =
-      g_strdup_printf (templ_VUYA_TO_PLANAR_CHROMA_BODY, div, div);
+      g_strdup_printf (templ_VUYA_TO_PLANAR_CHROMA_BODY, u, div, v, div);
 
   return TRUE;
 }
@@ -912,14 +971,18 @@ setup_convert_info_vuya_to_semi_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint div = 1;
+  guint div = 1;
+  gchar u, v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
+  get_semi_planar_component (out_info, &u, &v);
+
   info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
-  info->ps_body[1] = g_strdup_printf (templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY);
+  info->ps_body[1] =
+      g_strdup_printf (templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY, v, u);
 
   return TRUE;
 }
@@ -929,15 +992,16 @@ setup_convert_info_planar_to_vuya (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint mul = 1;
+  guint mul;
+  gchar u, v;
+
+  get_planar_component (in_info, &u, &v, &mul);
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_I420_10LE)
-    mul = 64;
-
-  info->ps_body[0] = g_strdup_printf (templ_PLANAR_to_VUYA_BODY, mul, mul, mul);
+  info->ps_body[0] =
+      g_strdup_printf (templ_PLANAR_to_VUYA_BODY, mul, u, mul, v, mul);
 
   return TRUE;
 }
@@ -967,11 +1031,14 @@ setup_convert_info_semi_planar_to_vuya (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
+  gchar u, v;
+
+  get_semi_planar_component (in_info, &u, &v);
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
-  info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_VUYA_BODY);
+  info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_VUYA_BODY, v, u);
 
   return TRUE;
 }
@@ -981,24 +1048,26 @@ setup_convert_info_packed_yuv_to_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint div = 1;
-  gchar y, u, v;
+  gchar in_y, in_u, in_v;
+  gchar out_u, out_v;
+  guint out_scale;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
 
-  if (GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420_10LE)
-    div = 64;
-
   if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
-          &y, &u, &v)) {
+          &in_y, &in_u, &in_v)) {
     return FALSE;
   }
 
-  info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, y, div);
+  get_planar_component (out_info, &out_u, &out_v, &out_scale);
+
+  info->ps_body[0] =
+      g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, out_scale);
   info->ps_body[1] =
-      g_strdup_printf (templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY, u, v, div, div);
+      g_strdup_printf (templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY, in_u, in_v,
+      out_u, out_scale, out_v, out_scale);
 
   return TRUE;
 }
@@ -1008,26 +1077,44 @@ setup_convert_info_packed_yuv_to_semi_planar (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
   ConvertInfo *info = &self->convert_info;
-  gint div = 1;
-  gchar y, u, v;
+  gchar in_y, in_u, in_v;
+  gchar out_u, out_v;
 
   info->templ = &templ_REORDER;
   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
 
   if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
-          &y, &u, &v)) {
+          &in_y, &in_u, &in_v)) {
     return FALSE;
   }
 
-  info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, y, div);
+  get_semi_planar_component (out_info, &out_u, &out_v);
+
+  info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, 1);
   info->ps_body[1] =
-      g_strdup_printf (templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY, u, v);
+      g_strdup_printf (templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY,
+      in_u, in_v, out_u, out_v);
 
   return TRUE;
 }
 
 static gboolean
+is_planar_format (const GstVideoInfo * info)
+{
+  switch (GST_VIDEO_INFO_FORMAT (info)) {
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_I420_10LE:
+      return TRUE;
+    default:
+      break;
+  }
+
+  return FALSE;
+}
+
+static gboolean
 setup_convert_info_yuv_to_yuv (GstD3D11Converter * self,
     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
 {
@@ -1037,15 +1124,13 @@ setup_convert_info_yuv_to_yuv (GstD3D11Converter * self,
 
   in_vuya = GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VUYA;
   out_vuya = GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_VUYA;
-  in_planar = (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_I420 ||
-      GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_I420_10LE);
+  in_planar = is_planar_format (in_info);
   in_packed = (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_YUY2 ||
       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_UYVY ||
       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VYUY ||
       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y210 ||
       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y410);
-  out_planar = (GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420 ||
-      GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_I420_10LE);
+  out_planar = is_planar_format (out_info);
 
   /* From/to VUYA */
   if (in_vuya && out_vuya) {
@@ -1786,10 +1871,13 @@ gst_d3d11_converter_update_viewport (GstD3D11Converter * converter,
 
   switch (GST_VIDEO_INFO_FORMAT (&converter->out_info)) {
     case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
     case GST_VIDEO_FORMAT_P010_10LE:
     case GST_VIDEO_FORMAT_P016_LE:
     case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_I420_10LE:{
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_I420_10LE:
+    {
       guint i;
       converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2;
       converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY / 2;
index 6cd010a..675a68e 100644 (file)
@@ -163,7 +163,7 @@ run_convert_pipelne (const gchar * in_format, const gchar * out_format)
 GST_START_TEST (test_d3d11_color_convert_yuv_yuv)
 {
   const gchar *format_list[] = {
-    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE"
+    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE", "YV12", "NV21"
   };
 
   gint i, j;
@@ -184,7 +184,7 @@ GST_END_TEST;
 GST_START_TEST (test_d3d11_color_convert_yuv_rgb)
 {
   const gchar *in_format_list[] = {
-    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE"
+    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE", "YV12", "NV21"
   };
   const gchar *out_format_list[] = {
     "BGRA", "RGBA", "RGB10A2_LE", "BGRx", "RGBx",
@@ -213,7 +213,7 @@ GST_START_TEST (test_d3d11_color_convert_rgb_yuv)
     "BGRA", "RGBA", "RGB10A2_LE", "BGRx", "RGBx",
   };
   const gchar *out_format_list[] = {
-    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE"
+    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE", "YV12", "NV21"
   };
 
   gint i, j;
@@ -256,7 +256,7 @@ GST_START_TEST (test_d3d11_color_convert_packed_yuv_yuv)
     "YUY2", "UYVY", "VYUY", "Y210", "Y410",
   };
   const gchar *out_format_list[] = {
-    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE"
+    "VUYA", "NV12", "P010_10LE", "P016_LE", "I420", "I420_10LE", "YV12", "NV21"
   };
 
   gint i, j;