ge2d: Add the function of using ge2d hardware to rotate [1/1]

PD#SWPL-40533

Problem:
use ge2d support rotation

Solution:
Add the function of using ge2d hardware to rotate

Verify:
W400 + buildroot

Change-Id: If4f75f14f8593d5ed3cb2e647aeab6480b9dd909
Signed-off-by: bo.li6 <bo.li6@amlogic.com>
diff --git a/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d.c b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d.c
new file mode 100644
index 0000000..a26a1af
--- /dev/null
+++ b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d.c
@@ -0,0 +1,37 @@
+/*
+ * gst_ge2d.c
+ *
+ *  Created on: 2020年11月3日
+ *      Author: tao
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "gst_ge2d_flip.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+    gboolean ret = FALSE;
+    ret |= gst_element_register(plugin, "ge2d_flip",
+            GST_RANK_PRIMARY,
+            GST_TYPE_GE2D_FLIP);
+    return ret;
+}
+
+#define PACKAGE "gst-aml-drm-plugins"
+#define GST_PACKAGE_ORIGIN "http://amlogic.com"
+
+GST_PLUGIN_DEFINE (
+    GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    ge2d,
+    "Amlogic plugin for ge2d",
+    plugin_init,
+    VERSION,
+    "LGPL",
+    PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN
+)
diff --git a/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.c b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.c
new file mode 100644
index 0000000..38464b0
--- /dev/null
+++ b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.c
@@ -0,0 +1,436 @@
+/*
+ * gst_ge2d_flip.c
+ *
+ *  Created on: 2020年11月3日
+ *      Author: tao
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <gst/allocators/gstdrmallocator.h>
+#include <gst/gstdrmbufferpool.h>
+#include "gst_ge2d_flip.h"
+
+enum
+{
+    PROP_0,
+    PROP_METHOD,
+    PROP_SECURE
+};
+#define ALIGN_PAD(x, y) (((x) + ((y)-1)) & (~((y)-1)))
+
+GST_DEBUG_CATEGORY_STATIC(gst_ge2d_flip_debug);
+#define GST_CAT_DEFAULT gst_ge2d_flip_debug
+
+#define VIDEO_CAPS "{ NV12, NV21 }"
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
+                                                                   GST_PAD_SINK,
+                                                                   GST_PAD_ALWAYS,
+                                                                   GST_STATIC_CAPS(
+                                                                       GST_VIDEO_CAPS_MAKE(VIDEO_CAPS)));
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE("src",
+                                                                  GST_PAD_SRC,
+                                                                  GST_PAD_SOMETIMES,
+                                                                  GST_STATIC_CAPS(
+                                                                      GST_VIDEO_CAPS_MAKE(VIDEO_CAPS)));
+
+#define gst_ge2d_flip_parent_class parent_class
+G_DEFINE_TYPE(GstGe2dFlip, gst_ge2d_flip, GST_TYPE_BASE_TRANSFORM);
+
+#define GST_TYPE_GE2D_FLIP_METHOD (gst_ge2d_flip_method_get_type())
+
+static const GEnumValue ge2d_flip_methods[] = {
+  {GST_VIDEO_ORIENTATION_IDENTITY, "Identity (no rotation)", "none"},
+  {GST_VIDEO_ORIENTATION_90R, "Rotate clockwise 90 degrees", "clockwise"},
+  {GST_VIDEO_ORIENTATION_180, "Rotate 180 degrees", "rotate-180"},
+  {GST_VIDEO_ORIENTATION_90L, "Rotate counter-clockwise 90 degrees",
+      "counterclockwise"},
+  {GST_VIDEO_ORIENTATION_HORIZ, "Flip horizontally", "horizontal-flip"},
+  {GST_VIDEO_ORIENTATION_VERT, "Flip vertically", "vertical-flip"},
+  {0, NULL, NULL},
+};
+
+static GType
+gst_ge2d_flip_method_get_type(void)
+{
+    static GType ge2d_flip_method_type = 0;
+
+    if (!ge2d_flip_method_type)
+    {
+        ge2d_flip_method_type = g_enum_register_static("GstGe2dFlipMethod",
+                                                       ge2d_flip_methods);
+    }
+    return ge2d_flip_method_type;
+}
+
+static void
+gst_ge2d_flip_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(object);
+
+    switch (prop_id)
+    {
+    case PROP_METHOD:
+        GST_OBJECT_LOCK(plugin);
+        plugin->method = g_value_get_enum(value);
+        GST_OBJECT_UNLOCK(plugin);
+        break;
+    case PROP_SECURE:
+        GST_OBJECT_LOCK(plugin);
+        plugin->secure = g_value_get_boolean(value);
+        GST_OBJECT_UNLOCK(plugin);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_ge2d_flip_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(object);
+
+    switch (prop_id)
+    {
+    case PROP_METHOD:
+        GST_OBJECT_LOCK(plugin);
+        g_value_set_enum(value, plugin->method);
+        GST_OBJECT_UNLOCK(plugin);
+        break;
+    case PROP_SECURE:
+        GST_OBJECT_LOCK(plugin);
+        g_value_set_boolean(value, plugin->secure);
+        GST_OBJECT_UNLOCK(plugin);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static gboolean
+gst_ge2d_flip_start(GstBaseTransform *trans)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+
+    int ret = 0;
+    plugin->pge2dinfo = &(plugin->amlge2d.ge2dinfo);
+
+    memset(&plugin->amlge2d, 0, sizeof(aml_ge2d_t));
+
+    /* ge2d init */
+    ret = aml_ge2d_init(&plugin->amlge2d);
+    if (ret < 0)
+    {
+        GST_ERROR("ge2d init failed");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static gboolean
+gst_ge2d_flip_stop(GstBaseTransform *trans)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+
+    //ge2d release exit
+    aml_ge2d_exit(&plugin->amlge2d);
+    return TRUE;
+}
+
+static gboolean
+gst_ge2d_flip_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+    if (!gst_video_info_from_caps(&plugin->in_info, incaps))
+        return FALSE;
+    if (!gst_video_info_from_caps(&plugin->out_info, outcaps))
+        return FALSE;
+    return TRUE;
+}
+
+static gboolean
+gst_ge2d_flip_propose_allocation(GstBaseTransform *trans, GstQuery *decide_query,
+                                 GstQuery *query)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+    GstCaps *caps;
+    GstBufferPool *pool = NULL;
+    gboolean need_pool;
+
+    gst_query_parse_allocation(query, &caps, &need_pool);
+
+    if (need_pool)
+    {
+        pool = gst_drm_bufferpool_new(plugin->secure, GST_DRM_BUFFERPOOL_TYPE_VIDEO_PLANE);
+    }
+
+    gst_query_add_allocation_pool(query, pool, 0, 2, 0);
+    if (pool)
+        g_object_unref(pool);
+
+    gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
+    return TRUE;
+}
+
+static gboolean
+gst_ge2d_flip_decide_allocation(GstBaseTransform *trans, GstQuery *query)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+    GstCaps *caps;
+    GstBufferPool *pool = NULL;
+    GstStructure *config;
+    guint size, min, max;
+
+    if (gst_query_get_n_allocation_pools(query) > 0)
+    {
+        gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
+        if (pool)
+            g_object_unref(pool);
+    }
+    gst_query_parse_allocation(query, &caps, NULL);
+
+    pool = gst_drm_bufferpool_new(plugin->secure, GST_DRM_BUFFERPOOL_TYPE_VIDEO_PLANE);
+    if (pool)
+    {
+        config = gst_buffer_pool_get_config(pool);
+        gst_buffer_pool_config_set_params(config, caps, size, min, max);
+        gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+        gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
+        gst_buffer_pool_set_config(pool, config);
+        gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
+        gst_object_unref(pool);
+    }
+    if (!gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL))
+    {
+        gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
+    };
+
+    return TRUE;
+}
+
+static GstCaps *
+gst_ge2d_flip_transform_caps(GstBaseTransform *trans, GstPadDirection direction,
+                             GstCaps *caps, GstCaps *filter)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+    GstCaps *ret = NULL;
+    gint width, height, i;
+
+    ret = gst_caps_copy(caps);
+
+    GST_DEBUG_OBJECT(plugin, "transform_caps direction:%d caps:%" GST_PTR_FORMAT, direction, caps);
+
+    for (i = 0; i < gst_caps_get_size(ret); i++)
+    {
+        GstStructure *structure = gst_caps_get_structure(ret, i);
+        gint par_n, par_d;
+
+        if (gst_structure_get_int(structure, "width", &width) &&
+            gst_structure_get_int(structure, "height", &height))
+        {
+            switch (plugin->method)
+            {
+            case GST_VIDEO_ORIENTATION_90R:
+            case GST_VIDEO_ORIENTATION_90L:
+                gst_structure_set(structure, "width", G_TYPE_INT, height,
+                                  "height", G_TYPE_INT, width, NULL);
+                if (gst_structure_get_fraction(structure, "pixel-aspect-ratio",
+                                               &par_n, &par_d))
+                {
+                    if (par_n != 1 || par_d != 1)
+                    {
+                        GValue val = {
+                            0,
+                        };
+
+                        g_value_init(&val, GST_TYPE_FRACTION);
+                        gst_value_set_fraction(&val, par_d, par_n);
+                        gst_structure_set_value(structure, "pixel-aspect-ratio", &val);
+                        g_value_unset(&val);
+                    }
+                }
+                break;
+            case GST_VIDEO_ORIENTATION_IDENTITY:
+            case GST_VIDEO_ORIENTATION_180:
+            case GST_VIDEO_ORIENTATION_HORIZ:
+            case GST_VIDEO_ORIENTATION_VERT:
+                gst_structure_set(structure, "width", G_TYPE_INT, width,
+                                  "height", G_TYPE_INT, height, NULL);
+
+                break;
+            default:
+                g_assert_not_reached();
+            }
+        }
+    }
+    GST_DEBUG_OBJECT(plugin, "transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, caps, ret);
+
+    if (filter)
+    {
+        GstCaps *intersection;
+
+        GST_DEBUG_OBJECT(plugin, "Using filter caps %" GST_PTR_FORMAT, filter);
+        intersection =
+            gst_caps_intersect_full(filter, ret, GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref(ret);
+        ret = intersection;
+        GST_DEBUG_OBJECT(plugin, "Intersection %" GST_PTR_FORMAT, ret);
+    }
+
+    return ret;
+}
+
+static GE2D_ROTATION pluginOriMethod2ge2d(GstVideoOrientationMethod pluginRotation)
+{
+    GE2D_ROTATION ge2dratation;
+    switch (pluginRotation)
+    {
+    case GST_VIDEO_ORIENTATION_90R:
+        ge2dratation = GE2D_ROTATION_90;
+        break;
+    case GST_VIDEO_ORIENTATION_180:
+        ge2dratation = GE2D_ROTATION_180;
+        break;
+    case GST_VIDEO_ORIENTATION_90L:
+        ge2dratation = GE2D_ROTATION_270;
+        break;
+    default:
+        ge2dratation = GE2D_ROTATION_0;
+        break;
+    }
+    return ge2dratation;
+}
+
+static GstFlowReturn
+gst_ge2d_flip_transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
+{
+    GstGe2dFlip *plugin = GST_GE2D_FLIP(trans);
+    GstFlowReturn ret = GST_FLOW_ERROR;
+    GstMemory *mem;
+    guint inbuf_n, outbuf_n;
+    int i;
+    int plane = GST_VIDEO_INFO_N_PLANES(&plugin->in_info);
+
+    aml_ge2d_info_t *pge2dinfo = plugin->pge2dinfo;
+
+    inbuf_n = gst_buffer_n_memory(inbuf);
+    outbuf_n = gst_buffer_n_memory(outbuf);
+
+    g_return_val_if_fail(inbuf_n == plane, ret);
+    g_return_val_if_fail(outbuf_n == plane, ret);
+
+    for (i = 0; i < plane; i++)
+    {
+        mem = gst_buffer_peek_memory(inbuf, i);
+        g_return_val_if_fail(gst_is_drm_memory(mem), ret);
+        pge2dinfo->src_info[0].shared_fd[i] = gst_fd_memory_get_fd(mem); /* input memory fd array, related to xx.plane_number */
+
+        mem = gst_buffer_peek_memory(outbuf, i);
+        g_return_val_if_fail(gst_is_drm_memory(mem), ret);
+        pge2dinfo->dst_info.shared_fd[i] = gst_fd_memory_get_fd(mem);
+    }
+
+    pge2dinfo->mem_sec = 1;
+
+    g_return_val_if_fail(inbuf_n == outbuf_n && inbuf_n > 0, ret);
+
+    pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
+    pge2dinfo->src_info[0].mem_alloc_type = AML_GE2D_MEM_DMABUF;
+    pge2dinfo->src_info[0].plane_number = plane;                               /* When allocating memory, it is a continuous block or separate multiple blocks */
+    pge2dinfo->src_info[0].canvas_w = ALIGN_PAD(GST_VIDEO_INFO_WIDTH(&plugin->in_info), 64); /* input width */
+    pge2dinfo->src_info[0].canvas_h = ALIGN_PAD(GST_VIDEO_INFO_HEIGHT(&plugin->in_info), 64); /* input height */
+    pge2dinfo->src_info[0].format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
+    pge2dinfo->src_info[0].rect.x = 0;                                       /* input process area x */
+    pge2dinfo->src_info[0].rect.y = 0;                                       /* input process area y */
+    pge2dinfo->src_info[0].rect.w = GST_VIDEO_INFO_WIDTH(&plugin->in_info);  /* input process area w */
+    pge2dinfo->src_info[0].rect.h = GST_VIDEO_INFO_HEIGHT(&plugin->in_info); /* input process area h */
+    pge2dinfo->src_info[0].plane_alpha = 0xFF;                               /* global plane alpha*/
+
+    pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
+    pge2dinfo->dst_info.mem_alloc_type = AML_GE2D_MEM_DMABUF;
+    pge2dinfo->dst_info.plane_number = plane;                                /* When allocating memory, it is a continuous block or separate multiple blocks */
+    pge2dinfo->dst_info.canvas_w = ALIGN_PAD(GST_VIDEO_INFO_WIDTH(&plugin->out_info), 64); /* output width */
+    pge2dinfo->dst_info.canvas_h = ALIGN_PAD(GST_VIDEO_INFO_HEIGHT(&plugin->out_info), 64); /* output width */
+    pge2dinfo->dst_info.format = PIXEL_FORMAT_YCbCr_420_SP_NV12;
+    pge2dinfo->dst_info.rect.x = 0;                                          /* output process area x */
+    pge2dinfo->dst_info.rect.y = 0;                                          /* output process area y */
+    pge2dinfo->dst_info.rect.w = GST_VIDEO_INFO_WIDTH(&plugin->out_info);    /* output process area w */
+    pge2dinfo->dst_info.rect.h = GST_VIDEO_INFO_HEIGHT(&plugin->out_info);   /* output process area h */
+    pge2dinfo->dst_info.plane_alpha = 0xFF;                                  /* global plane alpha*/
+
+    pge2dinfo->dst_info.rotation = pluginOriMethod2ge2d(plugin->method);
+    pge2dinfo->ge2d_op = AML_GE2D_STRETCHBLIT;
+
+    //ge2d begin rotation
+    ret = aml_ge2d_process(pge2dinfo);
+
+    if (ret < 0){
+        GST_ERROR("ge2d process failed, %s (%d)", __func__, __LINE__);
+        goto beach;
+    }
+
+    ret = GST_FLOW_OK;
+beach:
+    GST_ERROR("%s %d", __FUNCTION__, __LINE__);
+    return ret;
+}
+
+static void
+gst_ge2d_flip_class_init(GstGe2dFlipClass *klass)
+{
+    GObjectClass *gobject_class = (GObjectClass *)klass;
+    GstElementClass *element_class = (GstElementClass *)klass;
+    GstBaseTransformClass *base_class = GST_BASE_TRANSFORM_CLASS(klass);
+
+    GST_DEBUG_CATEGORY_INIT(gst_ge2d_flip_debug, "ge2d_flip", 0, "GE2D Flip");
+
+    gobject_class->set_property = gst_ge2d_flip_set_property;
+    gobject_class->get_property = gst_ge2d_flip_get_property;
+
+    base_class->start = GST_DEBUG_FUNCPTR(gst_ge2d_flip_start);
+    base_class->stop = GST_DEBUG_FUNCPTR(gst_ge2d_flip_stop);
+    base_class->set_caps = GST_DEBUG_FUNCPTR(gst_ge2d_flip_set_caps);
+    base_class->propose_allocation = GST_DEBUG_FUNCPTR(gst_ge2d_flip_propose_allocation);
+    base_class->decide_allocation = GST_DEBUG_FUNCPTR(gst_ge2d_flip_decide_allocation);
+    base_class->transform_caps = GST_DEBUG_FUNCPTR(gst_ge2d_flip_transform_caps);
+    base_class->transform = GST_DEBUG_FUNCPTR(gst_ge2d_flip_transform);
+    base_class->passthrough_on_same_caps = FALSE;
+    base_class->transform_ip_on_passthrough = FALSE;
+
+    gst_element_class_add_pad_template(element_class,
+                                       gst_static_pad_template_get(&sinktemplate));
+    gst_element_class_add_pad_template(element_class,
+                                       gst_static_pad_template_get(&srctemplate));
+
+    g_object_class_install_property(gobject_class, PROP_METHOD,
+                                    g_param_spec_enum("method", "method",
+                                                      "method (deprecated, use video-direction instead)",
+                                                      GST_TYPE_GE2D_FLIP_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
+                                                      GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+                                                          G_PARAM_STATIC_STRINGS));
+    g_object_class_install_property(gobject_class, PROP_SECURE,
+                                    g_param_spec_boolean("secure", "Use Secure",
+                                                         "Use Secure DRM based memory for allocation",
+                                                         FALSE, G_PARAM_WRITABLE));
+
+    gst_element_class_set_details_simple(element_class,
+                                         "Amlogic GE2D Plugin",
+                                         "Filter/Effect/Video",
+                                         "GE2D Plugin",
+                                         "mm@amlogic.com");
+}
+
+static void
+gst_ge2d_flip_init(GstGe2dFlip *plugin)
+{
+    GstBaseTransform *base = GST_BASE_TRANSFORM(plugin);
+    gst_base_transform_set_passthrough(base, FALSE);
+    gst_base_transform_set_in_place(base, FALSE);
+
+    plugin->secure = FALSE;
+}
diff --git a/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.h b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.h
new file mode 100644
index 0000000..a4f5fc1
--- /dev/null
+++ b/gst-aml-drm-plugins-1.0/src/ge2d/gst_ge2d_flip.h
@@ -0,0 +1,60 @@
+/*
+ * gst_ge2d_flip.h
+ *
+ *  Created on: 2020年11月3日
+ *      Author: tao
+ */
+
+#ifndef _GST_GE2D_FLIP_H_
+#define _GST_GE2D_FLIP_H_
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/video/video.h>
+#include <aml_ge2d.h>
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GE2D_FLIP \
+  (gst_ge2d_flip_get_type())
+#define GST_GE2D_FLIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GE2D_FLIP,GstGe2dFlip))
+#define GST_GE2D_FLIP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GE2D_FLIP,GstGe2dFlipClass))
+  #define GST_GE2D_FLIP_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GE2D_FLIP,GstGe2dFlipClass))
+#define GST_IS_GE2D_FLIP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GE2D_FLIP))
+#define GST_IS_GE2D_FLIP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GE2D_FLIP))
+
+
+typedef struct _GstGe2dFlip      GstGe2dFlip;
+typedef struct _GstGe2dFlipClass GstGe2dFlipClass;
+
+
+struct _GstGe2dFlip
+{
+    GstBaseTransform            videofilter;
+
+    GstVideoOrientationMethod   method;
+    gboolean                    secure;
+    GstVideoInfo                in_info;
+    GstVideoInfo                out_info;
+
+    int                         ret;
+    aml_ge2d_info_t             *pge2dinfo;
+    aml_ge2d_t                  amlge2d;
+};
+
+struct _GstGe2dFlipClass {
+    GstBaseTransformClass       parent_class;
+};
+
+
+GType gst_ge2d_flip_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GE2D_FLIP_H_ */