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; }
/* must be called with the object lock */ static gboolean gst_geometric_transform_generate_map (GstGeometricTransform * gt) { gint x, y; gdouble in_x, in_y; gboolean ret = TRUE; GstGeometricTransformClass *klass; gdouble *ptr; GST_INFO_OBJECT (gt, "Generating new transform map"); /* cleanup old map */ g_free (gt->map); gt->map = NULL; klass = GST_GEOMETRIC_TRANSFORM_GET_CLASS (gt); /* subclass must have defined the map_func */ g_return_val_if_fail (klass->map_func, FALSE); /* * (x,y) pairs of the inverse mapping */ gt->map = g_malloc0 (sizeof (gdouble) * gt->width * gt->height * 2); ptr = gt->map; for (y = 0; y < gt->height; y++) { for (x = 0; x < gt->width; x++) { if (!klass->map_func (gt, x, y, &in_x, &in_y)) { /* child should have warned */ ret = FALSE; goto end; } ptr[0] = in_x; ptr[1] = in_y; ptr += 2; } } end: if (!ret) { GST_WARNING_OBJECT (gt, "Generating transform map failed"); g_free (gt->map); gt->map = NULL; } else gt->needs_remap = FALSE; 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; }