gstglupload: make the GLMemoryUpload method output the correct texture-target
authorAlessandro Decina <alessandro.d@gmail.com>
Mon, 22 Aug 2016 07:18:27 +0000 (17:18 +1000)
committerAlessandro Decina <alessandro.d@gmail.com>
Fri, 26 Aug 2016 07:44:33 +0000 (17:44 +1000)
Now when used with video/x-raw as input, the GLMemoryUpload method checks for
->tex_target in input GLMemory(es) and sets the output texture-target
accordingly.

Fixes video corruption with a pipeline like avfvideosrc ! video/x-raw !
glimagesink where on macos avfvideosrc pushes RECTANGLE textures but glupload
was configuring texture-target=2D as output.

ext/gl/gstgluploadelement.c
gst-libs/gst/gl/gstglupload.c
gst-libs/gst/gl/gstglupload.h

index b65c0c4..f458a43 100644 (file)
@@ -97,6 +97,8 @@ static void
 gst_gl_upload_element_init (GstGLUploadElement * upload)
 {
   gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (upload), TRUE);
+
+  upload->upload = gst_gl_upload_new (NULL);
 }
 
 static gboolean
@@ -133,9 +135,11 @@ static GstCaps *
 _gst_gl_upload_element_transform_caps (GstBaseTransform * bt,
     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
 {
+  GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
   GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
 
-  return gst_gl_upload_transform_caps (context, direction, caps, filter);
+  return gst_gl_upload_transform_caps (upload->upload, context, direction, caps,
+      filter);
 }
 
 static gboolean
@@ -177,10 +181,10 @@ _gst_gl_upload_element_decide_allocation (GstBaseTransform * trans,
   if (!ret)
     return FALSE;
 
+  /* GstGLBaseFilter populates ->context in ::decide_allocation so now it's the
+   * time to set the ->upload context */
   context = GST_GL_BASE_FILTER (trans)->context;
-
-  if (!upload->upload)
-    upload->upload = gst_gl_upload_new (context);
+  gst_gl_upload_set_context (upload->upload, context);
 
   return gst_gl_upload_set_caps (upload->upload, upload->in_caps,
       upload->out_caps);
@@ -220,6 +224,10 @@ gst_gl_upload_element_prepare_output_buffer (GstBaseTransform * bt,
     return GST_FLOW_NOT_NEGOTIATED;
 
   ret = gst_gl_upload_perform_with_buffer (upload->upload, buffer, outbuf);
+  if (ret == GST_GL_UPLOAD_RECONFIGURE) {
+    gst_base_transform_reconfigure_src (bt);
+    return GST_FLOW_OK;
+  }
 
   if (ret != GST_GL_UPLOAD_DONE || *outbuf == NULL) {
     GST_ELEMENT_ERROR (bt, RESOURCE, NOT_FOUND, ("%s",
index 58107c5..7075944 100644 (file)
@@ -189,7 +189,7 @@ struct _UploadMethod
   GstStaticCaps *input_template_caps;
 
     gpointer (*new) (GstGLUpload * upload);
-  GstCaps *(*transform_caps) (GstGLContext * context,
+  GstCaps *(*transform_caps) (gpointer impl, GstGLContext * context,
       GstPadDirection direction, GstCaps * caps);
     gboolean (*accept) (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
       GstCaps * out_caps);
@@ -203,6 +203,7 @@ struct _UploadMethod
 struct GLMemoryUpload
 {
   GstGLUpload *upload;
+  GstGLTextureTarget input_target;
 };
 
 static gpointer
@@ -211,14 +212,16 @@ _gl_memory_upload_new (GstGLUpload * upload)
   struct GLMemoryUpload *mem = g_new0 (struct GLMemoryUpload, 1);
 
   mem->upload = upload;
+  mem->input_target = GST_GL_TEXTURE_TARGET_NONE;
 
   return mem;
 }
 
 static GstCaps *
-_gl_memory_upload_transform_caps (GstGLContext * context,
+_gl_memory_upload_transform_caps (gpointer impl, GstGLContext * context,
     GstPadDirection direction, GstCaps * caps)
 {
+  struct GLMemoryUpload *upload = impl;
   GstCapsFeatures *passthrough =
       gst_caps_features_from_string
       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
@@ -231,12 +234,17 @@ _gl_memory_upload_transform_caps (GstGLContext * context,
   gst_caps_features_free (passthrough);
 
   if (direction == GST_PAD_SINK) {
-    GstGLTextureTarget target_mask = 0;
     GstCaps *tmp;
+    GstGLTextureTarget target_mask;
+
+    if (upload->input_target != GST_GL_TEXTURE_TARGET_NONE) {
+      target_mask = 1 << upload->input_target;
+    } else {
+      target_mask = 1 << GST_GL_TEXTURE_TARGET_2D |
+          1 << GST_GL_TEXTURE_TARGET_RECTANGLE |
+          1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
+    }
 
-    target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D;
-    target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE;
-    target_mask |= 1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
     tmp = _caps_intersect_texture_target (ret, target_mask);
     gst_caps_unref (ret);
     ret = tmp;
@@ -412,6 +420,12 @@ _gl_memory_upload_perform (gpointer impl, GstBuffer * buffer,
             gl_mem->mem.context))
       return GST_GL_UPLOAD_UNSHARED_GL_CONTEXT;
 
+    if (upload->input_target != gl_mem->tex_target) {
+      upload->input_target = gl_mem->tex_target;
+      *outbuf = NULL;
+      return GST_GL_UPLOAD_RECONFIGURE;
+    }
+
     if (gst_is_gl_memory_pbo (mem))
       gst_gl_memory_pbo_upload_transfer ((GstGLMemoryPBO *) mem);
   }
@@ -466,7 +480,7 @@ _dma_buf_upload_new (GstGLUpload * upload)
 }
 
 static GstCaps *
-_dma_buf_upload_transform_caps (GstGLContext * context,
+_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
     GstPadDirection direction, GstCaps * caps)
 {
   GstCapsFeatures *passthrough =
@@ -714,13 +728,13 @@ _upload_meta_upload_new (GstGLUpload * upload)
   struct GLUploadMeta *meta = g_new0 (struct GLUploadMeta, 1);
 
   meta->upload = upload;
-  meta->pool = gst_gl_buffer_pool_new (upload->context);
+  meta->pool = NULL;
 
   return meta;
 }
 
 static GstCaps *
-_upload_meta_upload_transform_caps (GstGLContext * context,
+_upload_meta_upload_transform_caps (gpointer impl, GstGLContext * context,
     GstPadDirection direction, GstCaps * caps)
 {
   GstCapsFeatures *passthrough =
@@ -783,6 +797,9 @@ _upload_meta_upload_accept (gpointer impl, GstBuffer * buffer,
   if (!ret)
     return ret;
 
+  if (upload->pool == NULL)
+    upload->pool = gst_gl_buffer_pool_new (upload->upload->context);
+
   if (!gst_buffer_pool_is_active (upload->pool)) {
     config = gst_buffer_pool_get_config (upload->pool);
 
@@ -1012,7 +1029,7 @@ _raw_data_upload_new (GstGLUpload * upload)
 }
 
 static GstCaps *
-_raw_data_upload_transform_caps (GstGLContext * context,
+_raw_data_upload_transform_caps (gpointer impl, GstGLContext * context,
     GstPadDirection direction, GstCaps * caps)
 {
   GstCapsFeatures *passthrough =
@@ -1216,7 +1233,10 @@ gst_gl_upload_new (GstGLContext * context)
   GstGLUpload *upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL);
   gint i, n;
 
-  upload->context = gst_object_ref (context);
+  if (context)
+    gst_gl_upload_set_context (upload, context);
+  else
+    upload->context = NULL;
 
   n = G_N_ELEMENTS (upload_methods);
   upload->priv->upload_impl = g_malloc (sizeof (gpointer) * n);
@@ -1230,6 +1250,14 @@ gst_gl_upload_new (GstGLContext * context)
   return upload;
 }
 
+void
+gst_gl_upload_set_context (GstGLUpload * upload, GstGLContext * context)
+{
+  g_return_if_fail (upload != NULL);
+
+  gst_object_replace ((GstObject **) & upload->context, (GstObject *) context);
+}
+
 static void
 gst_gl_upload_finalize (GObject * object)
 {
@@ -1238,8 +1266,6 @@ gst_gl_upload_finalize (GObject * object)
 
   upload = GST_GL_UPLOAD (object);
 
-  if (upload->priv->method_impl)
-    upload->priv->method->free (upload->priv->method_impl);
   upload->priv->method_i = 0;
 
   if (upload->context) {
@@ -1268,8 +1294,8 @@ gst_gl_upload_finalize (GObject * object)
 }
 
 GstCaps *
-gst_gl_upload_transform_caps (GstGLContext * context, GstPadDirection direction,
-    GstCaps * caps, GstCaps * filter)
+gst_gl_upload_transform_caps (GstGLUpload * upload, GstGLContext * context,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
 {
   GstCaps *result, *tmp;
   gint i;
@@ -1279,7 +1305,9 @@ gst_gl_upload_transform_caps (GstGLContext * context, GstPadDirection direction,
   for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
     GstCaps *tmp2;
 
-    tmp2 = upload_methods[i]->transform_caps (context, direction, caps);
+    tmp2 =
+        upload_methods[i]->transform_caps (upload->priv->upload_impl[i],
+        context, direction, caps);
 
     if (tmp2)
       tmp = gst_caps_merge (tmp, tmp2);
@@ -1332,8 +1360,6 @@ _gst_gl_upload_set_caps_unlocked (GstGLUpload * upload, GstCaps * in_caps,
   gst_video_info_from_caps (&upload->priv->in_info, in_caps);
   gst_video_info_from_caps (&upload->priv->out_info, out_caps);
 
-  if (upload->priv->method_impl)
-    upload->priv->method->free (upload->priv->method_impl);
   upload->priv->method_impl = NULL;
   upload->priv->method_i = 0;
 
@@ -1388,16 +1414,14 @@ gst_gl_upload_get_caps (GstGLUpload * upload, GstCaps ** in_caps,
 static gboolean
 _upload_find_method (GstGLUpload * upload)
 {
+  gint method_i;
+
   if (upload->priv->method_i >= G_N_ELEMENTS (upload_methods))
     return FALSE;
 
-  if (upload->priv->method_impl) {
-    upload->priv->method->free (upload->priv->method_impl);
-    upload->priv->method_impl = NULL;
-  }
-
-  upload->priv->method = upload_methods[upload->priv->method_i];
-  upload->priv->method_impl = upload->priv->method->new (upload);
+  method_i = upload->priv->method_i;
+  upload->priv->method = upload_methods[method_i];
+  upload->priv->method_impl = upload->priv->upload_impl[method_i];
 
   GST_DEBUG_OBJECT (upload, "attempting upload with uploader %s",
       upload->priv->method->name);
@@ -1452,19 +1476,24 @@ restart:
       upload->priv->method->perform (upload->priv->method_impl, buffer,
       &outbuf);
   if (ret == GST_GL_UPLOAD_UNSHARED_GL_CONTEXT) {
-    upload->priv->method->free (upload->priv->method_impl);
-    upload->priv->method = &_raw_data_upload;
-    upload->priv->method_impl = upload->priv->method->new (upload);
+    for (int i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
+      if (upload_methods[i] == &_raw_data_upload) {
+        upload->priv->method = &_raw_data_upload;
+        upload->priv->method_impl = upload->priv->upload_impl[i];
+        upload->priv->method_i = i;
+
+        break;
+      }
+    }
     goto restart;
-  } else if (ret == GST_GL_UPLOAD_DONE) {
+  } else if (ret == GST_GL_UPLOAD_DONE || ret == GST_GL_UPLOAD_RECONFIGURE) {
     /* we are done */
   } else {
-    upload->priv->method->free (upload->priv->method_impl);
     upload->priv->method_impl = NULL;
     NEXT_METHOD;
   }
 
-  if (buffer != outbuf)
+  if (outbuf && buffer != outbuf)
     gst_buffer_copy_into (outbuf, buffer,
         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
   *outbuf_ptr = outbuf;
index 577c94b..d158502 100644 (file)
@@ -47,8 +47,9 @@ typedef enum
 
   GST_GL_UPLOAD_ERROR = -1,
   GST_GL_UPLOAD_UNSUPPORTED = -2,
+  GST_GL_UPLOAD_RECONFIGURE = -3,
   /* <private> */
-  GST_GL_UPLOAD_UNSHARED_GL_CONTEXT = -3,
+  GST_GL_UPLOAD_UNSHARED_GL_CONTEXT = -100,
 } GstGLUploadReturn;
 
 /**
@@ -82,7 +83,11 @@ GstCaps *     gst_gl_upload_get_input_template_caps (void);
 
 GstGLUpload * gst_gl_upload_new                    (GstGLContext * context);
 
-GstCaps *     gst_gl_upload_transform_caps         (GstGLContext * context,
+void          gst_gl_upload_set_context            (GstGLUpload * upload,
+                                                    GstGLContext * context);
+
+GstCaps *     gst_gl_upload_transform_caps         (GstGLUpload * upload,
+                                                    GstGLContext * context,
                                                     GstPadDirection direction,
                                                     GstCaps * caps,
                                                     GstCaps * filter);