gst/videotestsrc/: Add a zone plate pattern generator based on BBC R&D Report 1978...
authorJonathan Rosser <jonathan.rosser@rd.bbc.co.uk>
Fri, 21 Nov 2008 20:32:56 +0000 (20:32 +0000)
committerDavid Schleef <ds@schleef.org>
Fri, 21 Nov 2008 20:32:56 +0000 (20:32 +0000)
Original commit message from CVS:
Patch by: Jonathan Rosser <jonathan.rosser@rd.bbc.co.uk>
* gst/videotestsrc/gstvideotestsrc.c:
* gst/videotestsrc/gstvideotestsrc.h:
* gst/videotestsrc/videotestsrc.c:
* gst/videotestsrc/videotestsrc.h:
Add a zone plate pattern generator based on BBC R&D Report
1978/23 (yeah *that* 1978).  Try 'videotestsrc pattern=zone-plate
kx2=20 ky2=20 kt=1'.

ChangeLog
gst/videotestsrc/gstvideotestsrc.c
gst/videotestsrc/gstvideotestsrc.h
gst/videotestsrc/videotestsrc.c
gst/videotestsrc/videotestsrc.h

index b00410f..59f5616 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-11-21  David Schleef  <ds@schleef.org>
+
+       Patch by: Jonathan Rosser <jonathan.rosser@rd.bbc.co.uk>
+
+       * gst/videotestsrc/gstvideotestsrc.c:
+       * gst/videotestsrc/gstvideotestsrc.h:
+       * gst/videotestsrc/videotestsrc.c:
+       * gst/videotestsrc/videotestsrc.h:
+         Add a zone plate pattern generator based on BBC R&D Report
+         1978/23 (yeah *that* 1978).  Try 'videotestsrc pattern=zone-plate
+         kx2=20 ky2=20 kt=1'.
+
 2008-11-20  Michael Smith <msmith@songbirdnest.com>
 
        * gst/playback/gstdecodebin2.c:
index ce2837a..fc5133a 100644 (file)
@@ -66,6 +66,18 @@ enum
   PROP_IS_LIVE,
   PROP_PEER_ALLOC,
   PROP_COLOR_SPEC,
+  PROP_K0,
+  PROP_KX,
+  PROP_KY,
+  PROP_KT,
+  PROP_KXT,
+  PROP_KYT,
+  PROP_KXY,
+  PROP_KX2,
+  PROP_KY2,
+  PROP_KT2,
+  PROP_XOFFSET,
+  PROP_YOFFSET,
   PROP_LAST
 };
 
@@ -116,6 +128,7 @@ gst_video_test_src_pattern_get_type (void)
     {GST_VIDEO_TEST_SRC_CIRCULAR, "Circular", "circular"},
     {GST_VIDEO_TEST_SRC_BLINK, "Blink", "blink"},
     {GST_VIDEO_TEST_SRC_SMPTE75, "SMPTE 75% color bars", "smpte75"},
+    {GST_VIDEO_TEST_SRC_ZONE_PLATE, "Zone plate", "zone-plate"},
     {0, NULL, NULL}
   };
 
@@ -191,6 +204,61 @@ gst_video_test_src_class_init (GstVideoTestSrcClass * klass)
           "Generate video in the given color specification",
           GST_TYPE_VIDEO_TEST_SRC_COLOR_SPEC,
           DEFAULT_COLOR_SPEC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_K0,
+      g_param_spec_int ("k0", "Zoneplate zero order phase",
+          "Zoneplate zero order phase, for generating plain fields or phase offsets",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KX,
+      g_param_spec_int ("kx", "Zoneplate 1st order x phase",
+          "Zoneplate 1st order x phase, for generating constant horizontal frequencies",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KY,
+      g_param_spec_int ("ky", "Zoneplate 1st order y phase",
+          "Zoneplate 1st order y phase, for generating contant vertical frequencies",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KT,
+      g_param_spec_int ("kt", "Zoneplate 1st order t phase",
+          "Zoneplate 1st order t phase, for generating phase rotation as a function of time",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KXT,
+      g_param_spec_int ("kxt", "Zoneplate x*t product phase",
+          "Zoneplate x*t product phase, normalised to kxy/256 cycles per vertical pixel at width/2 from origin",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KYT,
+      g_param_spec_int ("kyt", "Zoneplate y*t product phase",
+          "Zoneplate y*t product phase", G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KXY,
+      g_param_spec_int ("kxy", "Zoneplate x*y product phase",
+          "Zoneplate x*t product phase", G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KX2,
+      g_param_spec_int ("kx2", "Zoneplate 2nd order x phase",
+          "Zoneplate 2nd order x phase, normalised to kx2/256 cycles per horizontal pixel at width/2 from origin",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KY2,
+      g_param_spec_int ("ky2", "Zoneplate 2nd order y phase",
+          "Zoneplate 2nd order y phase, normailsed to ky2/256 cycles per vertical pixel at height/2 from origin",
+          G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_KT2,
+      g_param_spec_int ("kt2", "Zoneplate 2nd order t phase",
+          "Zoneplate 2nd order t phase, t*t/256 cycles per picture", G_MININT32,
+          G_MAXINT32, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_XOFFSET,
+      g_param_spec_int ("xoffset", "Zoneplate 2nd order products x offset",
+          "Zoneplate 2nd order products x offset", G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_YOFFSET,
+      g_param_spec_int ("yoffset", "Zoneplate 2nd order products y offset",
+          "Zoneplate 2nd order products y offset", G_MININT32, G_MAXINT32, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gstbasesrc_class->get_caps = gst_video_test_src_getcaps;
   gstbasesrc_class->set_caps = gst_video_test_src_setcaps;
@@ -283,6 +351,9 @@ gst_video_test_src_set_pattern (GstVideoTestSrc * videotestsrc,
     case GST_VIDEO_TEST_SRC_SMPTE75:
       videotestsrc->make_image = gst_video_test_src_smpte75;
       break;
+    case GST_VIDEO_TEST_SRC_ZONE_PLATE:
+      videotestsrc->make_image = gst_video_test_src_zoneplate;
+      break;
     default:
       g_assert_not_reached ();
   }
@@ -310,6 +381,42 @@ gst_video_test_src_set_property (GObject * object, guint prop_id,
     case PROP_COLOR_SPEC:
       src->color_spec = g_value_get_enum (value);
       break;
+    case PROP_K0:
+      src->k0 = g_value_get_int (value);
+      break;
+    case PROP_KX:
+      src->kx = g_value_get_int (value);
+      break;
+    case PROP_KY:
+      src->ky = g_value_get_int (value);
+      break;
+    case PROP_KT:
+      src->kt = g_value_get_int (value);
+      break;
+    case PROP_KXT:
+      src->kxt = g_value_get_int (value);
+      break;
+    case PROP_KYT:
+      src->kyt = g_value_get_int (value);
+      break;
+    case PROP_KXY:
+      src->kxy = g_value_get_int (value);
+      break;
+    case PROP_KX2:
+      src->kx2 = g_value_get_int (value);
+      break;
+    case PROP_KY2:
+      src->ky2 = g_value_get_int (value);
+      break;
+    case PROP_KT2:
+      src->kt2 = g_value_get_int (value);
+      break;
+    case PROP_XOFFSET:
+      src->xoffset = g_value_get_int (value);
+      break;
+    case PROP_YOFFSET:
+      src->yoffset = g_value_get_int (value);
+      break;
     default:
       break;
   }
@@ -337,6 +444,42 @@ gst_video_test_src_get_property (GObject * object, guint prop_id,
     case PROP_COLOR_SPEC:
       g_value_set_enum (value, src->color_spec);
       break;
+    case PROP_K0:
+      g_value_set_int (value, src->k0);
+      break;
+    case PROP_KX:
+      g_value_set_int (value, src->kx);
+      break;
+    case PROP_KY:
+      g_value_set_int (value, src->ky);
+      break;
+    case PROP_KT:
+      g_value_set_int (value, src->kt);
+      break;
+    case PROP_KXT:
+      g_value_set_int (value, src->kxt);
+      break;
+    case PROP_KYT:
+      g_value_set_int (value, src->kyt);
+      break;
+    case PROP_KXY:
+      g_value_set_int (value, src->kxy);
+      break;
+    case PROP_KX2:
+      g_value_set_int (value, src->kx2);
+      break;
+    case PROP_KY2:
+      g_value_set_int (value, src->ky2);
+      break;
+    case PROP_KT2:
+      g_value_set_int (value, src->kt2);
+      break;
+    case PROP_XOFFSET:
+      g_value_set_int (value, src->xoffset);
+      break;
+    case PROP_YOFFSET:
+      g_value_set_int (value, src->yoffset);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index 36efcb7..0f9706b 100644 (file)
@@ -53,6 +53,7 @@ G_BEGIN_DECLS
  * @GST_VIDEO_TEST_SRC_CIRCULAR: Circular pattern
  * @GST_VIDEO_TEST_SRC_BLINK: Alternate between black and white
  * @GST_VIDEO_TEST_SRC_SMPTE75: SMPTE test pattern (75% color bars)
+ * @GST_VIDEO_TEST_SRC_ZONE_PLATE: Zone plate
  *
  * The test pattern to produce.
  */
@@ -70,7 +71,8 @@ typedef enum {
   GST_VIDEO_TEST_SRC_CHECKERS8,
   GST_VIDEO_TEST_SRC_CIRCULAR,
   GST_VIDEO_TEST_SRC_BLINK,
-  GST_VIDEO_TEST_SRC_SMPTE75
+  GST_VIDEO_TEST_SRC_SMPTE75,
+  GST_VIDEO_TEST_SRC_ZONE_PLATE
 } GstVideoTestSrcPattern;
 
 /**
@@ -119,6 +121,20 @@ struct _GstVideoTestSrc {
   gint64 n_frames;                      /* total frames sent */
   gboolean peer_alloc;
 
+  /* zoneplate */
+  gint k0;
+  gint kx;
+  gint ky;
+  gint kt;
+  gint kxt;
+  gint kyt;
+  gint kxy;
+  gint kx2;
+  gint ky2;
+  gint kt2;
+  gint xoffset;
+  gint yoffset;
+  
   void (*make_image) (GstVideoTestSrc *v, unsigned char *dest, int w, int h);
 };
 
index 8b0180e..b9f29fb 100644 (file)
@@ -1061,6 +1061,158 @@ gst_video_test_src_checkers8 (GstVideoTestSrc * v, guchar * dest, int w, int h)
   }
 }
 
+void
+gst_video_test_src_zoneplate (GstVideoTestSrc * v, unsigned char *dest,
+    int w, int h)
+{
+  int i;
+  int j;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+  struct vts_color_struct_rgb rgb_color;
+  struct vts_color_struct_yuv yuv_color;
+  static uint8_t sine_array[256];
+  static int sine_array_inited = FALSE;
+
+  static int t = 0;             /* time - increment phase vs time by 1 for each generated frame */
+  /* this may not fit with the correct gstreamer notion of time, so maybe FIXME? */
+
+  int xreset = -(w / 2) - v->xoffset;   /* starting values for x^2 and y^2, centering the ellipse */
+  int yreset = -(h / 2) - v->yoffset;
+
+  int x, y;
+  int accum_kx;
+  int accum_kxt;
+  int accum_ky;
+  int accum_kyt;
+  int accum_kxy;
+  int kt;
+  int kt2;
+  int ky2;
+  int delta_kxt = v->kxt * t;
+  int delta_kxy;
+  int scale_kxy = 0xffff / (w / 2);
+  int scale_kx2 = 0xffff / w;
+
+  if (!sine_array_inited) {
+    int black = 16;
+    int white = 235;
+    int range = white - black;
+    for (i = 0; i < 256; i++) {
+      sine_array[i] =
+          floor (range * (0.5 + 0.5 * sin (i * 2 * M_PI / 256)) + 0.5 + black);
+    }
+    sine_array_inited = TRUE;
+  }
+
+  p->rgb_colors = vts_colors_rgb;
+  if (v->color_spec == GST_VIDEO_TEST_SRC_BT601) {
+    p->yuv_colors = vts_colors_bt601_ycbcr_100;
+  } else {
+    p->yuv_colors = vts_colors_bt709_ycbcr_100;
+  }
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  rgb_color = p->rgb_colors[COLOR_BLACK];
+  yuv_color = p->yuv_colors[COLOR_BLACK];
+  p->rgb_color = &rgb_color;
+  p->yuv_color = &yuv_color;
+
+  /* Zoneplate equation:
+   *
+   * phase = k0 + kx*x + ky*y + kt*t
+   *       + kxt*x*t + kyt*y*t + kxy*x*y
+   *       + kx2*x*x + ky2*y*y + Kt2*t*t
+   */
+
+#if 0
+  for (j = 0, y = yreset; j < h; j++, y++) {
+    for (i = 0, x = xreset; i < w; i++, x++) {
+
+      //zero order
+      int phase = v->k0;
+
+      //first order
+      phase = phase + (v->kx * i) + (v->ky * j) + (v->kt * t);
+
+      //cross term
+      //phase = phase + (v->kxt * i * t) + (v->kyt * j * t);
+      //phase = phase + (v->kxy * x * y) / (w/2);
+
+      /*second order */
+      /*normalise x/y terms to rate of change of phase at the picture edge */
+      phase =
+          phase + ((v->kx2 * x * x) / w) + ((v->ky2 * y * y) / h) +
+          ((v->kt2 * t * t) >> 1);
+
+      color.Y = sine_array[phase & 0xff];
+
+      color.R = color.Y;
+      color.G = color.Y;
+      color.B = color.Y;
+      p->paint_hline (p, i, j, 1);
+    }
+  }
+#endif
+
+  /* optimised version, with original code shown in comments */
+  accum_ky = 0;
+  accum_kyt = 0;
+  kt = v->kt * t;
+  kt2 = v->kt2 * t * t;
+  for (j = 0, y = yreset; j < h; j++, y++) {
+    accum_kx = 0;
+    accum_kxt = 0;
+    accum_ky += v->ky;
+    accum_kyt += v->kyt * t;
+    delta_kxy = v->kxy * y * scale_kxy;
+    accum_kxy = delta_kxy * xreset;
+    ky2 = (v->ky2 * y * y) / h;
+    for (i = 0, x = xreset; i < w; i++, x++) {
+
+      //zero order
+      int phase = v->k0;
+
+      //first order
+      accum_kx += v->kx;
+      //phase = phase + (v->kx * i) + (v->ky * j) + (v->kt * t);
+      phase = phase + accum_kx + accum_ky + kt;
+
+      //cross term
+      accum_kxt += delta_kxt;
+      accum_kxy += delta_kxy;
+      //phase = phase + (v->kxt * i * t) + (v->kyt * j * t);
+      phase = phase + accum_kxt + accum_kyt;
+
+      //phase = phase + (v->kxy * x * y) / (w/2);
+      //phase = phase + accum_kxy / (w/2) ;
+      phase = phase + (accum_kxy >> 16);
+
+      /*second order */
+      /*normalise x/y terms to rate of change of phase at the picture edge */
+      //phase = phase + ((v->kx2 * x * x)/w) + ((v->ky2 * y * y)/h) + ((v->kt2 * t * t)>>1);
+      phase = phase + ((v->kx2 * x * x * scale_kx2) >> 16) + ky2 + (kt2 >> 1);
+
+      yuv_color.Y = sine_array[phase & 0xff];
+
+      rgb_color.R = yuv_color.Y;
+      rgb_color.G = yuv_color.Y;
+      rgb_color.B = yuv_color.Y;
+      p->paint_hline (p, i, j, 1);
+    }
+  }
+
+  t++;
+}
+
 #undef SCALE_AMPLITUDE
 void
 gst_video_test_src_circular (GstVideoTestSrc * v, unsigned char *dest,
@@ -1155,6 +1307,8 @@ gst_video_test_src_circular (GstVideoTestSrc * v, unsigned char *dest,
   }
 }
 
+
+
 static void
 paint_setup_I420 (paintinfo * p, unsigned char *dest)
 {
index 80f4ea1..e23c39e 100644 (file)
@@ -106,7 +106,8 @@ void    gst_video_test_src_checkers8    (GstVideoTestSrc * v,
                                          unsigned char *dest, int w, int h);
 void    gst_video_test_src_circular     (GstVideoTestSrc * v,
                                          unsigned char *dest, int w, int h);
-
+void    gst_video_test_src_zoneplate    (GstVideoTestSrc * v,
+                                        unsigned char *dest, int w, int h);
 extern struct fourcc_list_struct fourcc_list[];
 extern int n_fourccs;