video-anc: Handle SD formats correctly
authorSebastian Dröge <sebastian@centricular.com>
Mon, 22 Apr 2019 14:06:09 +0000 (17:06 +0300)
committerTim-Philipp Müller <tim@centricular.com>
Tue, 6 Aug 2019 15:33:41 +0000 (16:33 +0100)
VANC is stored linearly in SD formats instead of separating the Y and YV
components from each other and having first all Y and then all UV
values.

gst-libs/gst/video/video-anc.c
tests/check/libs/videoanc.c

index 6c7d305..0374e27 100644 (file)
@@ -404,13 +404,24 @@ convert_line_from_uyvy (GstVideoVBIParser * parser, const guint8 * data)
 {
   guint i;
   guint8 *y = parser->work_data;
-  guint8 *uv = y + parser->info.width;
 
-  for (i = 0; i < parser->info.width - 3; i += 4) {
-    *uv++ = data[(i / 4) * 4 + 0];
-    *y++ = data[(i / 4) * 4 + 1];
-    *uv++ = data[(i / 4) * 4 + 2];
-    *y++ = data[(i / 4) * 4 + 3];
+  /* Data is stored differently in SD, making no distinction between Y and UV */
+  if (parser->info.width < 1280) {
+    for (i = 0; i < parser->info.width - 3; i += 4) {
+      *y++ = data[(i / 4) * 4 + 0];
+      *y++ = data[(i / 4) * 4 + 1];
+      *y++ = data[(i / 4) * 4 + 2];
+      *y++ = data[(i / 4) * 4 + 3];
+    }
+  } else {
+    guint8 *uv = y + parser->info.width;
+
+    for (i = 0; i < parser->info.width - 3; i += 4) {
+      *uv++ = data[(i / 4) * 4 + 0];
+      *y++ = data[(i / 4) * 4 + 1];
+      *uv++ = data[(i / 4) * 4 + 2];
+      *y++ = data[(i / 4) * 4 + 3];
+    }
   }
   GST_MEMDUMP ("Converted line", parser->work_data, 128);
 }
@@ -446,30 +457,57 @@ convert_line_from_v210 (GstVideoVBIParser * parser, const guint8 * data)
 {
   guint i;
   guint16 *y = (guint16 *) parser->work_data;
-  guint16 *uv = y + parser->info.width;
   guint32 a, b, c, d;
 
-  /* Convert the line */
-  for (i = 0; i < parser->info.width - 5; i += 6) {
-    a = GST_READ_UINT32_LE (data + (i / 6) * 16 + 0);
-    b = GST_READ_UINT32_LE (data + (i / 6) * 16 + 4);
-    c = GST_READ_UINT32_LE (data + (i / 6) * 16 + 8);
-    d = GST_READ_UINT32_LE (data + (i / 6) * 16 + 12);
-
-    *uv++ = (a >> 0) & 0x3ff;
-    *y++ = (a >> 10) & 0x3ff;
-    *uv++ = (a >> 20) & 0x3ff;
-    *y++ = (b >> 0) & 0x3ff;
-
-    *uv++ = (b >> 10) & 0x3ff;
-    *y++ = (b >> 20) & 0x3ff;
-    *uv++ = (c >> 0) & 0x3ff;
-    *y++ = (c >> 10) & 0x3ff;
-
-    *uv++ = (c >> 20) & 0x3ff;
-    *y++ = (d >> 0) & 0x3ff;
-    *uv++ = (d >> 10) & 0x3ff;
-    *y++ = (d >> 20) & 0x3ff;
+  /* Data is stored differently in SD, making no distinction between Y and UV */
+  if (parser->info.width < 1280) {
+    /* Convert the line */
+    for (i = 0; i < parser->info.width - 5; i += 6) {
+      a = GST_READ_UINT32_LE (data + (i / 6) * 16 + 0);
+      b = GST_READ_UINT32_LE (data + (i / 6) * 16 + 4);
+      c = GST_READ_UINT32_LE (data + (i / 6) * 16 + 8);
+      d = GST_READ_UINT32_LE (data + (i / 6) * 16 + 12);
+
+      *y++ = (a >> 0) & 0x3ff;
+      *y++ = (a >> 10) & 0x3ff;
+      *y++ = (a >> 20) & 0x3ff;
+      *y++ = (b >> 0) & 0x3ff;
+
+      *y++ = (b >> 10) & 0x3ff;
+      *y++ = (b >> 20) & 0x3ff;
+      *y++ = (c >> 0) & 0x3ff;
+      *y++ = (c >> 10) & 0x3ff;
+
+      *y++ = (c >> 20) & 0x3ff;
+      *y++ = (d >> 0) & 0x3ff;
+      *y++ = (d >> 10) & 0x3ff;
+      *y++ = (d >> 20) & 0x3ff;
+    }
+  } else {
+    guint16 *uv = y + parser->info.width;
+
+    /* Convert the line */
+    for (i = 0; i < parser->info.width - 5; i += 6) {
+      a = GST_READ_UINT32_LE (data + (i / 6) * 16 + 0);
+      b = GST_READ_UINT32_LE (data + (i / 6) * 16 + 4);
+      c = GST_READ_UINT32_LE (data + (i / 6) * 16 + 8);
+      d = GST_READ_UINT32_LE (data + (i / 6) * 16 + 12);
+
+      *uv++ = (a >> 0) & 0x3ff;
+      *y++ = (a >> 10) & 0x3ff;
+      *uv++ = (a >> 20) & 0x3ff;
+      *y++ = (b >> 0) & 0x3ff;
+
+      *uv++ = (b >> 10) & 0x3ff;
+      *y++ = (b >> 20) & 0x3ff;
+      *uv++ = (c >> 0) & 0x3ff;
+      *y++ = (c >> 10) & 0x3ff;
+
+      *uv++ = (c >> 20) & 0x3ff;
+      *y++ = (d >> 0) & 0x3ff;
+      *uv++ = (d >> 10) & 0x3ff;
+      *y++ = (d >> 20) & 0x3ff;
+    }
   }
 
   if (0) {
@@ -767,39 +805,71 @@ convert_line_to_v210 (GstVideoVBIEncoder * encoder, guint8 * data)
 {
   guint i;
   const guint16 *y = (const guint16 *) encoder->work_data;
-  const guint16 *uv = y + encoder->info.width;
   guint32 a, b, c, d;
 
-  /* Convert the line */
-  for (i = 0; i < encoder->info.width - 5; i += 6) {
-    a = ((uv[0] & 0x3ff) << 0)
-        | ((y[0] & 0x3ff) << 10)
-        | ((uv[1] & 0x3ff) << 20);
-    uv += 2;
-    y++;
-
-    b = ((y[0] & 0x3ff) << 0)
-        | ((uv[0] & 0x3ff) << 10)
-        | ((y[1] & 0x3ff) << 20);
-    y += 2;
-    uv++;
-
-    c = ((uv[0] & 0x3ff) << 0)
-        | ((y[0] & 0x3ff) << 10)
-        | ((uv[1] & 0x3ff) << 20);
-    uv += 2;
-    y++;
-
-    d = ((y[0] & 0x3ff) << 0)
-        | ((uv[0] & 0x3ff) << 10)
-        | ((y[1] & 0x3ff) << 20);
-    y += 2;
-    uv++;
-
-    GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 0, a);
-    GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 4, b);
-    GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 8, c);
-    GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 12, d);
+  /* Data is stored differently in SD, making no distinction between Y and UV */
+  if (encoder->info.width < 1280) {
+    /* Convert the line */
+    for (i = 0; i < encoder->info.width - 5; i += 6) {
+      a = ((y[0] & 0x3ff) << 0)
+          | ((y[1] & 0x3ff) << 10)
+          | ((y[2] & 0x3ff) << 20);
+      y += 3;
+
+      b = ((y[0] & 0x3ff) << 0)
+          | ((y[1] & 0x3ff) << 10)
+          | ((y[2] & 0x3ff) << 20);
+      y += 3;
+
+      c = ((y[0] & 0x3ff) << 0)
+          | ((y[1] & 0x3ff) << 10)
+          | ((y[2] & 0x3ff) << 20);
+      y += 3;
+
+      d = ((y[0] & 0x3ff) << 0)
+          | ((y[1] & 0x3ff) << 10)
+          | ((y[2] & 0x3ff) << 20);
+      y += 3;
+
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 0, a);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 4, b);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 8, c);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 12, d);
+    }
+  } else {
+    const guint16 *uv = y + encoder->info.width;
+
+    /* Convert the line */
+    for (i = 0; i < encoder->info.width - 5; i += 6) {
+      a = ((uv[0] & 0x3ff) << 0)
+          | ((y[0] & 0x3ff) << 10)
+          | ((uv[1] & 0x3ff) << 20);
+      uv += 2;
+      y++;
+
+      b = ((y[0] & 0x3ff) << 0)
+          | ((uv[0] & 0x3ff) << 10)
+          | ((y[1] & 0x3ff) << 20);
+      y += 2;
+      uv++;
+
+      c = ((uv[0] & 0x3ff) << 0)
+          | ((y[0] & 0x3ff) << 10)
+          | ((uv[1] & 0x3ff) << 20);
+      uv += 2;
+      y++;
+
+      d = ((y[0] & 0x3ff) << 0)
+          | ((uv[0] & 0x3ff) << 10)
+          | ((y[1] & 0x3ff) << 20);
+      y += 2;
+      uv++;
+
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 0, a);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 4, b);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 8, c);
+      GST_WRITE_UINT32_LE (data + (i / 6) * 16 + 12, d);
+    }
   }
 }
 
@@ -808,13 +878,24 @@ convert_line_to_uyvy (GstVideoVBIEncoder * encoder, guint8 * data)
 {
   guint i;
   const guint8 *y = encoder->work_data;
-  const guint8 *uv = y + encoder->info.width;
 
-  for (i = 0; i < encoder->info.width - 3; i += 4) {
-    data[(i / 4) * 4 + 0] = *uv++;
-    data[(i / 4) * 4 + 1] = *y++;
-    data[(i / 4) * 4 + 2] = *uv++;
-    data[(i / 4) * 4 + 3] = *y++;
+  /* Data is stored differently in SD, making no distinction between Y and UV */
+  if (encoder->info.width < 1280) {
+    for (i = 0; i < encoder->info.width - 3; i += 4) {
+      data[(i / 4) * 4 + 0] = *y++;
+      data[(i / 4) * 4 + 1] = *y++;
+      data[(i / 4) * 4 + 2] = *y++;
+      data[(i / 4) * 4 + 3] = *y++;
+    }
+  } else {
+    const guint8 *uv = y + encoder->info.width;
+
+    for (i = 0; i < encoder->info.width - 3; i += 4) {
+      data[(i / 4) * 4 + 0] = *uv++;
+      data[(i / 4) * 4 + 1] = *y++;
+      data[(i / 4) * 4 + 2] = *uv++;
+      data[(i / 4) * 4 + 3] = *y++;
+    }
   }
 }
 
index 967ad69..11a50d5 100644 (file)
 GST_START_TEST (parse_8bit)
 {
   GstVideoVBIParser *parser;
-  guint8 line[1440] = { 0, };
+  guint8 line[2560] = { 0, };
   GstVideoAncillary vanc;
 
-  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_UYVY, 720);
+  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_UYVY, 1280);
   fail_unless (parser != NULL);
 
   /* empty line */
@@ -124,10 +124,10 @@ GST_END_TEST;
 GST_START_TEST (parse_10bit)
 {
   GstVideoVBIParser *parser;
-  guint8 line[1920] = { 0, };
+  guint8 line[3414] = { 0, };
   GstVideoAncillary vanc;
 
-  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_v210, 720);
+  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_v210, 1280);
   fail_unless (parser != NULL);
 
   /* empty line */
@@ -220,15 +220,15 @@ GST_START_TEST (encode_8bit)
 {
   GstVideoVBIParser *parser;
   GstVideoVBIEncoder *encoder;
-  guint8 line[1440] = { 0, };
+  guint8 line[2560] = { 0, };
   const guint8 data1[] = { 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80 };
   const guint8 data2[] = { 0x04, 0x03, 0x02, 0x01 };
   GstVideoAncillary vanc;
 
-  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_UYVY, 720);
+  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_UYVY, 1280);
   fail_unless (parser != NULL);
 
-  encoder = gst_video_vbi_encoder_new (GST_VIDEO_FORMAT_UYVY, 720);
+  encoder = gst_video_vbi_encoder_new (GST_VIDEO_FORMAT_UYVY, 1280);
   fail_unless (encoder != NULL);
 
   /* Write a single ADF packet and try to parse it back again */
@@ -282,15 +282,15 @@ GST_START_TEST (encode_10bit)
 {
   GstVideoVBIParser *parser;
   GstVideoVBIEncoder *encoder;
-  guint8 line[1920] = { 0, };
+  guint8 line[3414] = { 0, };
   const guint8 data1[] = { 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80 };
   const guint8 data2[] = { 0x04, 0x03, 0x02, 0x01 };
   GstVideoAncillary vanc;
 
-  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_v210, 720);
+  parser = gst_video_vbi_parser_new (GST_VIDEO_FORMAT_v210, 1280);
   fail_unless (parser != NULL);
 
-  encoder = gst_video_vbi_encoder_new (GST_VIDEO_FORMAT_v210, 720);
+  encoder = gst_video_vbi_encoder_new (GST_VIDEO_FORMAT_v210, 1280);
   fail_unless (encoder != NULL);
 
   /* Write a single ADF packet and try to parse it back again */