static GstFlowReturn
gst_geometric_transform_transform (GstBaseTransform * trans, GstBuffer * buf,
    GstBuffer * outbuf)
{
  GstGeometricTransform *gt;
  GstGeometricTransformClass *klass;
  gint x, y;
  GstFlowReturn ret = GST_FLOW_OK;
  gdouble *ptr;

  gt = GST_GEOMETRIC_TRANSFORM_CAST (trans);
  klass = GST_GEOMETRIC_TRANSFORM_GET_CLASS (gt);

  memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));

  GST_OBJECT_LOCK (gt);
  if (gt->precalc_map) {
    if (gt->needs_remap) {
      if (klass->prepare_func)
        if (!klass->prepare_func (gt)) {
          GST_OBJECT_UNLOCK (gt);
          return FALSE;
        }
      gst_geometric_transform_generate_map (gt);
    }
    g_return_val_if_fail (gt->map, GST_FLOW_ERROR);
    ptr = gt->map;
    for (y = 0; y < gt->height; y++) {
      for (x = 0; x < gt->width; x++) {
        /* do the mapping */
        gst_geometric_transform_do_map (gt, buf, outbuf, x, y, ptr[0], ptr[1]);
        ptr += 2;
      }
    }
  } else {
    for (y = 0; y < gt->height; y++) {
      for (x = 0; x < gt->width; x++) {
        gdouble in_x, in_y;

        if (klass->map_func (gt, x, y, &in_x, &in_y)) {
          gst_geometric_transform_do_map (gt, buf, outbuf, x, y, in_x, in_y);
        } else {
          GST_WARNING_OBJECT (gt, "Failed to do mapping for %d %d", x, y);
          ret = GST_FLOW_ERROR;
          goto end;
        }
      }
    }
  }
end:
  GST_OBJECT_UNLOCK (gt);
  return ret;
}
static GstFlowReturn
gst_geometric_transform_transform_frame (GstVideoFilter * vfilter,
    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
{
  GstGeometricTransform *gt;
  GstGeometricTransformClass *klass;
  gint x, y;
  GstFlowReturn ret = GST_FLOW_OK;
  gdouble *ptr;
  guint8 *in_data;
  guint8 *out_data;

  gt = GST_GEOMETRIC_TRANSFORM_CAST (vfilter);
  klass = GST_GEOMETRIC_TRANSFORM_GET_CLASS (gt);

  in_data = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
  out_data = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);

  if (GST_VIDEO_FRAME_FORMAT (out_frame) == GST_VIDEO_FORMAT_AYUV) {
    /* in AYUV black is not just all zeros:
     * 0x10 is black for Y,
     * 0x80 is black for Cr and Cb */
    for (int i = 0; i < out_frame->map[0].size; i += 4)
      GST_WRITE_UINT32_BE (out_data + i, 0xff108080);
  } else {
    memset (out_data, 0, out_frame->map[0].size);
  }

  GST_OBJECT_LOCK (gt);
  if (gt->precalc_map) {
    if (gt->needs_remap) {
      if (klass->prepare_func)
        if (!klass->prepare_func (gt)) {
          ret = FALSE;
          goto end;
        }
      gst_geometric_transform_generate_map (gt);
    }
    g_return_val_if_fail (gt->map, GST_FLOW_ERROR);
    ptr = gt->map;
    for (y = 0; y < gt->height; y++) {
      for (x = 0; x < gt->width; x++) {
        /* do the mapping */
        gst_geometric_transform_do_map (gt, in_data, out_data, x, y, ptr[0],
            ptr[1]);
        ptr += 2;
      }
    }
  } else {
    for (y = 0; y < gt->height; y++) {
      for (x = 0; x < gt->width; x++) {
        gdouble in_x, in_y;

        if (klass->map_func (gt, x, y, &in_x, &in_y)) {
          gst_geometric_transform_do_map (gt, in_data, out_data, x, y, in_x,
              in_y);
        } else {
          GST_WARNING_OBJECT (gt, "Failed to do mapping for %d %d", x, y);
          ret = GST_FLOW_ERROR;
          goto end;
        }
      }
    }
  }
end:
  GST_OBJECT_UNLOCK (gt);
  return ret;
}