ivtc: implement new edge-directed upsampling
authorDavid Schleef <ds@schleef.org>
Wed, 31 Jul 2013 18:54:06 +0000 (11:54 -0700)
committerDavid Schleef <ds@schleef.org>
Sun, 4 Aug 2013 06:29:10 +0000 (23:29 -0700)
gst/ivtc/gstivtc.c

index 3ece8e6..a377537 100644 (file)
@@ -351,6 +351,24 @@ reconstruct (GstIvtc * ivtc, GstVideoFrame * dest_frame, int i1, int i2)
 
 }
 
+static int
+reconstruct_line (guint8 * line1, guint8 * line2, int i, int a, int b, int c,
+    int d)
+{
+  int x;
+
+  x = line1[i - 3] * a;
+  x += line1[i - 2] * b;
+  x += line1[i - 1] * c;
+  x += line1[i - 0] * d;
+  x += line2[i + 0] * d;
+  x += line2[i + 1] * c;
+  x += line2[i + 2] * b;
+  x += line2[i + 3] * a;
+  return (x + 16) >> 5;
+}
+
+
 static void
 reconstruct_single (GstIvtc * ivtc, GstVideoFrame * dest_frame, int i1)
 {
@@ -360,7 +378,77 @@ reconstruct_single (GstIvtc * ivtc, GstVideoFrame * dest_frame, int i1)
   int width;
   GstIvtcField *field = &ivtc->fields[i1];
 
-  for (k = 0; k < 3; k++) {
+  for (k = 0; k < 1; k++) {
+    height = GST_VIDEO_FRAME_COMP_HEIGHT (dest_frame, k);
+    width = GST_VIDEO_FRAME_COMP_WIDTH (dest_frame, k);
+    for (j = 0; j < height; j++) {
+      if ((j & 1) == field->parity) {
+        memcpy (GET_LINE (dest_frame, k, j),
+            GET_LINE (&field->frame, k, j), width);
+      } else {
+        if (j == 0 || j == height - 1) {
+          memcpy (GET_LINE (dest_frame, k, j),
+              GET_LINE (&field->frame, k, (j ^ 1)), width);
+        } else {
+          guint8 *dest = GET_LINE (dest_frame, k, j);
+          guint8 *line1 = GET_LINE (&field->frame, k, j - 1);
+          guint8 *line2 = GET_LINE (&field->frame, k, j + 1);
+          int i;
+
+#define MARGIN 3
+          for (i = MARGIN; i < width - MARGIN; i++) {
+            int dx, dy;
+
+            dx = -line1[i - 1] - line2[i - 1] + line1[i + 1] + line2[i + 1];
+            dx *= 2;
+
+            dy = -line1[i - 1] - 2 * line1[i] - line1[i + 1]
+                + line2[i - 1] + 2 * line2[i] + line2[i + 1];
+            if (dy < 0) {
+              dy = -dy;
+              dx = -dx;
+            }
+
+            if (dx == 0 && dy == 0) {
+              dest[i] = (line1[i] + line2[i] + 1) >> 1;
+            } else if (dx < 0) {
+              if (dx < -2 * dy) {
+                dest[i] = reconstruct_line (line1, line2, i, 0, 0, 0, 16);
+              } else if (dx < -dy) {
+                dest[i] = reconstruct_line (line1, line2, i, 0, 0, 8, 8);
+              } else if (2 * dx < -dy) {
+                dest[i] = reconstruct_line (line1, line2, i, 0, 4, 8, 4);
+              } else if (3 * dx < -dy) {
+                dest[i] = reconstruct_line (line1, line2, i, 1, 7, 7, 1);
+              } else {
+                dest[i] = reconstruct_line (line1, line2, i, 4, 8, 4, 0);
+              }
+            } else {
+              if (dx > 2 * dy) {
+                dest[i] = reconstruct_line (line2, line1, i, 0, 0, 0, 16);
+              } else if (dx > dy) {
+                dest[i] = reconstruct_line (line2, line1, i, 0, 0, 8, 8);
+              } else if (2 * dx > dy) {
+                dest[i] = reconstruct_line (line2, line1, i, 0, 4, 8, 4);
+              } else if (3 * dx > dy) {
+                dest[i] = reconstruct_line (line2, line1, i, 1, 7, 7, 1);
+              } else {
+                dest[i] = reconstruct_line (line2, line1, i, 4, 8, 4, 0);
+              }
+            }
+          }
+
+          for (i = 0; i < MARGIN; i++) {
+            dest[i] = (line1[i] + line2[i] + 1) >> 1;
+          }
+          for (i = width - MARGIN; i < width; i++) {
+            dest[i] = (line1[i] + line2[i] + 1) >> 1;
+          }
+        }
+      }
+    }
+  }
+  for (k = 1; k < 3; k++) {
     height = GST_VIDEO_FRAME_COMP_HEIGHT (dest_frame, k);
     width = GST_VIDEO_FRAME_COMP_WIDTH (dest_frame, k);
     for (j = 0; j < height; j++) {