From 226e80315925bb722cfdd5716e078832f3f6b3c4 Mon Sep 17 00:00:00 2001
From: Haihua Hu <b55597@freescale.com>
Date: Fri, 13 Nov 2015 10:51:25 +0800
Subject: [PATCH] support video crop for glimagesink

1.Add video crop meta copy in glupload
2.Calculate the new texture coordinate in vertices array and bind to buffer object
3.Make glimagesink only updating vertices array when video crop meta changed

Upstream-Status: Inappropriate [i.MX specific]

Signed-off-by: Haihua Hu <b55597@freescale.com>
Signed-off-by: Lyon Wang <lyon.wang@freescale.com>
---
 ext/gl/gstglimagesink.c     | 58 +++++++++++++++++++++++++++++++++++++++++++++
 ext/gl/gstglimagesink.h     |  3 +++
 ext/gl/gstgluploadelement.c | 14 +++++++++--
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/ext/gl/gstglimagesink.c b/ext/gl/gstglimagesink.c
index 0bac4fb1c118..196757adfbac 100644
--- a/ext/gl/gstglimagesink.c
+++ b/ext/gl/gstglimagesink.c
@@ -601,6 +601,8 @@ gst_glimage_sink_init (GstGLImageSink * glimage_sink)
   glimage_sink->handle_events = TRUE;
   glimage_sink->ignore_alpha = TRUE;
   glimage_sink->overlay_compositor = NULL;
+  glimage_sink->cropmeta = NULL;
+  glimage_sink->prev_cropmeta = NULL;
 
   glimage_sink->mview_output_mode = DEFAULT_MULTIVIEW_MODE;
   glimage_sink->mview_output_flags = DEFAULT_MULTIVIEW_FLAGS;
@@ -1062,6 +1064,12 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
         gst_object_unref (glimage_sink->display);
         glimage_sink->display = NULL;
       }
+
+      glimage_sink->cropmeta = NULL;
+      if (glimage_sink->prev_cropmeta)
+        g_slice_free(GstVideoCropMeta, glimage_sink->prev_cropmeta);
+      glimage_sink->prev_cropmeta = NULL;
+
       break;
     default:
       break;
@@ -1546,6 +1554,8 @@ gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
       GST_VIDEO_SINK_WIDTH (glimage_sink),
       GST_VIDEO_SINK_HEIGHT (glimage_sink));
 
+  glimage_sink->cropmeta = gst_buffer_get_video_crop_meta (buf);
+
   /* Ask the underlying window to redraw its content */
   if (!gst_glimage_sink_redisplay (glimage_sink))
     goto redisplay_failed;
@@ -2028,6 +2038,54 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink)
 
     gst_gl_shader_use (gl_sink->redisplay_shader);
 
+    if (gl_sink->cropmeta) {
+      gint width = GST_VIDEO_SINK_WIDTH (gl_sink);
+      gint height = GST_VIDEO_SINK_HEIGHT (gl_sink);
+
+      if (!gl_sink->prev_cropmeta){
+        /* Initialize the previous crop meta and set all memroy to zero */
+        gl_sink->prev_cropmeta = (GstVideoCropMeta *) g_slice_new0(GstVideoCropMeta);
+      }
+
+      /* If crop meta not equal to the previous, recalculate the vertices */
+      if (gl_sink->prev_cropmeta->x != gl_sink->cropmeta->x
+        || gl_sink->prev_cropmeta->y != gl_sink->cropmeta->y
+        || gl_sink->prev_cropmeta->width != gl_sink->cropmeta->width
+        || gl_sink->prev_cropmeta->height != gl_sink->cropmeta->height){
+
+	GLfloat crop_vertices[] = {
+	     1.0f,  1.0f, 0.0f, 1.0f, 0.0f,
+	    -1.0f,  1.0f, 0.0f, 0.0f, 0.0f,
+	    -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
+	     1.0f, -1.0f, 0.0f, 1.0f, 1.0f
+	};
+
+        crop_vertices[8] = (float)(gl_sink->cropmeta->x) / width;
+        crop_vertices[9] = (float)(gl_sink->cropmeta->y) / height;
+
+        crop_vertices[3] = (float)(gl_sink->cropmeta->width + gl_sink->cropmeta->x) / width;
+        crop_vertices[4] = crop_vertices[9];
+
+        crop_vertices[13] = crop_vertices[8];
+        crop_vertices[14] = (float)(gl_sink->cropmeta->height + gl_sink->cropmeta->y) / height;
+
+        crop_vertices[18] = crop_vertices[3];
+        crop_vertices[19] = crop_vertices[14];
+
+        gl->BindBuffer (GL_ARRAY_BUFFER, gl_sink->vertex_buffer);
+        gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), crop_vertices,
+            GL_STATIC_DRAW);
+
+        gl->BindBuffer (GL_ARRAY_BUFFER, 0);
+
+        /* Store the previous crop meta */
+        gl_sink->prev_cropmeta->x = gl_sink->cropmeta->x;
+        gl_sink->prev_cropmeta->y = gl_sink->cropmeta->y;
+        gl_sink->prev_cropmeta->width = gl_sink->cropmeta->width;
+        gl_sink->prev_cropmeta->height = gl_sink->cropmeta->height;
+      }
+    }
+
     if (gl->GenVertexArrays)
       gl->BindVertexArray (gl_sink->vao);
     else
diff --git a/ext/gl/gstglimagesink.h b/ext/gl/gstglimagesink.h
index 6e9b98e74a88..317055a016ed 100644
--- a/ext/gl/gstglimagesink.h
+++ b/ext/gl/gstglimagesink.h
@@ -107,6 +107,9 @@ struct _GstGLImageSink
     guint window_width;
     guint window_height;
 
+    GstVideoCropMeta *cropmeta;
+    GstVideoCropMeta *prev_cropmeta;
+
     GstVideoRectangle display_rect;
 
     GstGLShader *redisplay_shader;
diff --git a/ext/gl/gstgluploadelement.c b/ext/gl/gstgluploadelement.c
index 86e8b01e2407..1738c2f81c1d 100644
--- a/ext/gl/gstgluploadelement.c
+++ b/ext/gl/gstgluploadelement.c
@@ -232,9 +232,19 @@ gst_gl_upload_element_prepare_output_buffer (GstBaseTransform * bt,
   /* basetransform doesn't unref if they're the same */
   if (buffer == *outbuf)
     gst_buffer_unref (*outbuf);
-  else
+  else {
+    GstVideoCropMeta *incropmeta, *outcropmeta;
+    /* add video crop meta to out buffer if need */
+    incropmeta = gst_buffer_get_video_crop_meta (buffer);
+    if (incropmeta) {
+      outcropmeta = gst_buffer_add_video_crop_meta (*outbuf);
+      outcropmeta->x = incropmeta->x;
+      outcropmeta->y = incropmeta->y;
+      outcropmeta->width = incropmeta->width;
+      outcropmeta->height = incropmeta->height;
+    }
     bclass->copy_metadata (bt, buffer, *outbuf);
-
+  }
   return GST_FLOW_OK;
 }
 
