Merge "Fix compatibility with glvideoflip"
diff --git a/plugins/glsvgoverlaysink.py b/plugins/glsvgoverlaysink.py
index 6f800b6..75957df 100644
--- a/plugins/glsvgoverlaysink.py
+++ b/plugins/glsvgoverlaysink.py
@@ -36,11 +36,12 @@
 from OpenGL.GLES3 import (
     glActiveTexture, glBindBuffer, glBindTexture, glBindVertexArray, glBlendEquation, glBlendFunc,
     glBufferData, glDeleteBuffers, glDeleteVertexArrays, glDisable, glDrawElements, glEnable,
-    glEnableVertexAttribArray, glGenBuffers, glGenVertexArrays, glVertexAttribPointer,glViewport)
+    glEnableVertexAttribArray, glGenBuffers, glGenVertexArrays, glGetUniformLocation,
+    glUniformMatrix4fv, glVertexAttribPointer, glViewport)
 from OpenGL.GLES3 import (
     GL_ARRAY_BUFFER, GL_BLEND, GL_ELEMENT_ARRAY_BUFFER, GL_FALSE, GL_FLOAT, GL_FUNC_ADD,
     GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_STATIC_DRAW, GL_TEXTURE0, GL_TEXTURE_2D,
-    GL_TRIANGLES, GL_UNSIGNED_SHORT)
+    GL_TRIANGLES, GL_UNSIGNED_SHORT, GL_VERTEX_SHADER)
 
 # Gst.Buffer.map(Gst.MapFlags.WRITE) is broken, this is a workaround. See
 # http://lifestyletransfer.com/how-to-make-gstreamer-buffer-writable-in-python/
@@ -130,6 +131,18 @@
     assert GstGL.is_gl_memory(memory)
     return libgstgl.gst_gl_memory_get_texture_id(hash(memory))
 
+VERTEX_SHADER_SRC = '''
+    uniform mat4 u_transformation;
+    attribute vec4 a_position;
+    attribute vec2 a_texcoord;
+    varying vec2 v_texcoord;
+    void main()
+    {
+       gl_Position = u_transformation * a_position;
+       v_texcoord = a_texcoord;
+    }
+'''
+
 POSITIONS = numpy.array([
          1.0,  1.0,
         -1.0,  1.0,
@@ -148,6 +161,27 @@
          0, 1, 2, 0, 2, 3
     ], dtype=numpy.uint16)
 
+IDENTITY_MATRIX = numpy.array([
+        [1.0, 0.0, 0.0, 0.0],
+        [0.0, 1.0, 0.0, 0.0],
+        [0.0, 0.0, 1.0, 0.0],
+        [0.0, 0.0, 0.0, 1.0],
+    ], dtype=numpy.float16)
+
+HFLIP_MATRIX = numpy.array([
+        [-1.0, 0.0, 0.0, 0.0],
+        [ 0.0, 1.0, 0.0, 0.0],
+        [ 0.0, 0.0, 1.0, 0.0],
+        [ 0.0, 0.0, 0.0, 1.0],
+    ], dtype=numpy.float16)
+
+VFLIP_MATRIX = numpy.array([
+      [1.0,  0.0, 0.0, 0.0],
+      [0.0, -1.0, 0.0, 0.0],
+      [0.0,  0.0, 1.0, 0.0],
+      [0.0,  0.0, 0.0, 1.0],
+    ], dtype=numpy.float16)
+
 NUM_BUFFERS = 2
 
 class DmaOverlayBuffer():
@@ -221,6 +255,12 @@
             '',
             GObject.ParamFlags.WRITABLE
             ),
+        'rotate-method': (str,
+            'Rotate method',
+            'Rotate method according to glimagesink',
+            'none',
+            GObject.ParamFlags.WRITABLE
+            ),
         }
     __gsignals__ = {
         'drawn': (GObject.SignalFlags.RUN_LAST, None, ())
@@ -233,6 +273,7 @@
         self.positions_buffer = 0
         self.texcoords_buffer = 0
         self.vbo_indices = 0
+        self.u_transformation = 0
         self.glcontext = None
         self.glimagesink = Gst.ElementFactory.make('glimagesink')
         self.add(self.glimagesink)
@@ -241,12 +282,15 @@
         self.glimagesink.connect('client-reshape', self.on_reshape)
         self.glimagesink.get_static_pad('sink').add_probe(
             Gst.PadProbeType.EVENT_UPSTREAM, self.on_glimagesink_event)
+        self.get_static_pad('sink').add_probe(
+            Gst.PadProbeType.QUERY_DOWNSTREAM, self.on_downstream_query)
         self.render_thread = None
         self.cond = threading.Condition()
         self.rendering = False
         self.svg = None
         self.buffers = [None] * NUM_BUFFERS
         self.index = 0
+        self.matrix = IDENTITY_MATRIX
 
         self.print_fps = int(os.environ.get('PRINT_FPS', '0'))
         self.incoming_frames = 0
@@ -276,6 +320,27 @@
             return Gst.PadProbeReturn.DROP
         return Gst.PadProbeReturn.OK
 
+    def on_downstream_query(self, pad, info):
+        query = info.get_query()
+        if query.type == Gst.QueryType.ALLOCATION:
+            # Ask glimagesink, but remove the metas we don't support.
+            # Need to fiddle with refcount as Python bindings are buggy.
+            # refcount is really 1, but Python took another ref making
+            # it 2 and hence query is 'not writable'.
+            assert query.mini_object.refcount == 2
+            try:
+                query.mini_object.refcount = 1
+                if self.glimagesink.get_static_pad('sink').query(query):
+                    for i in reversed(range(0, query.get_n_allocation_metas())):
+                        gtype, params = query.parse_nth_allocation_meta(i)
+                        if (gtype.name == 'GstVideoAffineTransformationAPI' or
+                            gtype.name == 'GstVideoOverlayCompositionMetaAPI'):
+                            query.remove_nth_allocation_meta(i)
+                    return Gst.PadProbeReturn.HANDLED
+            finally:
+                query.mini_object.refcount = 2
+        return Gst.PadProbeReturn.OK
+
     def on_glimagesink_event(self, pad, info):
         event = info.get_event()
         if event.type == Gst.EventType.RECONFIGURE:
@@ -331,8 +396,21 @@
                 self.incoming_overlays += 1
                 self.svg = value or ''
                 self.cond.notify_all()
+        elif prop.name == 'rotate-method':
+            value = int(value) if value.isnumeric() else value
+            self.glimagesink.set_property(prop.name, value)
+            value = int(self.glimagesink.get_property(prop.name))
+            if value == 0:
+                self.matrix = IDENTITY_MATRIX
+            elif value == 4:
+                self.matrix = HFLIP_MATRIX
+            elif value == 5:
+                self.matrix = VFLIP_MATRIX
+            else:
+                Gst.warning('Unsupported rotate-method')
+                self.matrix = IDENTITY_MATRIX
         else:
-            self.glimagesink.set_property(prop, value)
+            self.glimagesink.set_property(prop.name, value)
 
     def do_get_property(self, prop):
         return self.glimagesink.get_property(prop)
@@ -341,7 +419,20 @@
         assert not self.shader
         assert glcontext == self.glcontext
 
-        self.shader = GstGL.GLShader.new_default(self.glcontext)
+        frag_stage = GstGL.GLSLStage.new_default_fragment(self.glcontext)
+        vert_stage = GstGL.GLSLStage.new_with_string(self.glcontext,
+            GL_VERTEX_SHADER,
+            GstGL.GLSLVersion.NONE,
+            GstGL.GLSLProfile.COMPATIBILITY | GstGL.GLSLProfile.ES,
+            VERTEX_SHADER_SRC)
+        self.shader = GstGL.GLShader.new(self.glcontext)
+        self.shader.compile_attach_stage(vert_stage)
+        self.shader.compile_attach_stage(frag_stage)
+        self.shader.link()
+
+        self.u_transformation = glGetUniformLocation.baseFunction(
+            self.shader.get_program_handle(), 'u_transformation')
+
         a_position = self.shader.get_attribute_location('a_position')
         a_texcoord = self.shader.get_attribute_location('a_texcoord')
 
@@ -432,6 +523,7 @@
 
         self.shader.use()
         self.shader.set_uniform_1i('frame', 0)
+        glUniformMatrix4fv(self.u_transformation, 1, GL_FALSE, self.matrix)
 
         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, None)
 
@@ -440,6 +532,7 @@
             glEnable(GL_BLEND)
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
             glBlendEquation(GL_FUNC_ADD)
+            glUniformMatrix4fv(self.u_transformation, 1, GL_FALSE, IDENTITY_MATRIX)
             glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, None)
 
         glActiveTexture(GL_TEXTURE0)