glupload: try to use the last method after reconfigure
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / gstglupload.c
1 /*
2  * GStreamer
3  * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
4  * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27
28 #include "gl.h"
29 #include "gstglupload.h"
30
31 #if GST_GL_HAVE_PLATFORM_EGL
32 #include "egl/gsteglimage.h"
33 #include "egl/gstglmemoryegl.h"
34 #include "egl/gstglcontext_egl.h"
35 #endif
36
37 #if GST_GL_HAVE_DMABUF
38 #include <gst/allocators/gstdmabuf.h>
39 #endif
40
41 #if GST_GL_HAVE_VIV_DIRECTVIV
42 #include <gst/allocators/gstphysmemory.h>
43 #include <gst/gl/gstglfuncs.h>
44 #endif
45
46 /**
47  * SECTION:gstglupload
48  * @title: GstGLUpload
49  * @short_description: an object that uploads to GL textures
50  * @see_also: #GstGLDownload, #GstGLMemory
51  *
52  * #GstGLUpload is an object that uploads data from system memory into GL textures.
53  *
54  * A #GstGLUpload can be created with gst_gl_upload_new()
55  */
56
57 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
58 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
59 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
60 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
61 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
62
63 GST_DEBUG_CATEGORY_STATIC (gst_gl_upload_debug);
64 #define GST_CAT_DEFAULT gst_gl_upload_debug
65
66 static void gst_gl_upload_finalize (GObject * object);
67
68 static GstGLTextureTarget
69 _caps_get_texture_target (GstCaps * caps, GstGLTextureTarget default_target)
70 {
71   GstGLTextureTarget ret = 0;
72   GstStructure *s = gst_caps_get_structure (caps, 0);
73
74   if (gst_structure_has_field_typed (s, "texture-target", G_TYPE_STRING)) {
75     const gchar *target_str = gst_structure_get_string (s, "texture-target");
76     ret = gst_gl_texture_target_from_string (target_str);
77   }
78
79   if (!ret)
80     ret = default_target;
81
82   return ret;
83 }
84
85 /* Define the maximum number of planes we can upload - handle 2 views per buffer */
86 #define GST_GL_UPLOAD_MAX_PLANES (GST_VIDEO_MAX_PLANES * 2)
87
88 typedef struct _UploadMethod UploadMethod;
89
90 struct _GstGLUploadPrivate
91 {
92   GstVideoInfo in_info;
93   GstVideoInfo out_info;
94   GstCaps *in_caps;
95   GstCaps *out_caps;
96
97   GstBuffer *outbuf;
98
99   /* all method impl pointers */
100   gpointer *upload_impl;
101
102   /* current method */
103   const UploadMethod *method;
104   gpointer method_impl;
105   int method_i;
106
107   /* saved method for reconfigure */
108   int saved_method_i;
109 };
110
111 #define DEBUG_INIT \
112   GST_DEBUG_CATEGORY_INIT (gst_gl_upload_debug, "glupload", 0, "upload");
113
114 G_DEFINE_TYPE_WITH_CODE (GstGLUpload, gst_gl_upload, GST_TYPE_OBJECT,
115     G_ADD_PRIVATE (GstGLUpload) DEBUG_INIT);
116
117 static GstCaps *
118 _set_caps_features_with_passthrough (const GstCaps * caps,
119     const gchar * feature_name, GstCapsFeatures * passthrough)
120 {
121   guint i, j, m, n;
122   GstCaps *tmp;
123
124   tmp = gst_caps_new_empty ();
125
126   n = gst_caps_get_size (caps);
127   for (i = 0; i < n; i++) {
128     GstCapsFeatures *features, *orig_features;
129     GstStructure *s = gst_caps_get_structure (caps, i);
130
131     orig_features = gst_caps_get_features (caps, i);
132     features = gst_caps_features_new (feature_name, NULL);
133
134     if (gst_caps_features_is_any (orig_features)) {
135       /* if we have any features, we add both the features with and without @passthrough */
136       gst_caps_append_structure_full (tmp, gst_structure_copy (s),
137           gst_caps_features_copy (features));
138
139       m = gst_caps_features_get_size (passthrough);
140       for (j = 0; j < m; j++) {
141         const gchar *feature = gst_caps_features_get_nth (passthrough, j);
142
143         /* if we already have the features */
144         if (gst_caps_features_contains (features, feature))
145           continue;
146
147         gst_caps_features_add (features, feature);
148       }
149     } else {
150       m = gst_caps_features_get_size (orig_features);
151       for (j = 0; j < m; j++) {
152         const gchar *feature = gst_caps_features_get_nth (orig_features, j);
153
154         /* if we already have the features */
155         if (gst_caps_features_contains (features, feature))
156           continue;
157
158         if (g_strcmp0 (feature, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) == 0)
159           continue;
160
161         if (gst_caps_features_contains (passthrough, feature)) {
162           gst_caps_features_add (features, feature);
163         }
164       }
165     }
166
167     gst_caps_append_structure_full (tmp, gst_structure_copy (s), features);
168   }
169
170   return tmp;
171 }
172
173 static GstCaps *
174 _caps_intersect_texture_target (GstCaps * caps, GstGLTextureTarget target_mask)
175 {
176   GValue targets = G_VALUE_INIT;
177   GstCaps *ret, *target;
178
179   target = gst_caps_copy (caps);
180   gst_gl_value_set_texture_target_from_mask (&targets, target_mask);
181   gst_caps_set_value (target, "texture-target", &targets);
182
183   ret = gst_caps_intersect_full (caps, target, GST_CAPS_INTERSECT_FIRST);
184
185   g_value_unset (&targets);
186   gst_caps_unref (target);
187   return ret;
188 }
189
190 typedef enum
191 {
192   METHOD_FLAG_CAN_SHARE_CONTEXT = 1,
193 } GstGLUploadMethodFlags;
194
195 struct _UploadMethod
196 {
197   const gchar *name;
198   GstGLUploadMethodFlags flags;
199
200   GstStaticCaps *input_template_caps;
201
202     gpointer (*new) (GstGLUpload * upload);
203   GstCaps *(*transform_caps) (gpointer impl, GstGLContext * context,
204       GstPadDirection direction, GstCaps * caps);
205     gboolean (*accept) (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
206       GstCaps * out_caps);
207   void (*propose_allocation) (gpointer impl, GstQuery * decide_query,
208       GstQuery * query);
209     GstGLUploadReturn (*perform) (gpointer impl, GstBuffer * buffer,
210       GstBuffer ** outbuf);
211   void (*free) (gpointer impl);
212 } _UploadMethod;
213
214 struct GLMemoryUpload
215 {
216   GstGLUpload *upload;
217   GstGLTextureTarget input_target;
218   GstGLTextureTarget output_target;
219 };
220
221 static gpointer
222 _gl_memory_upload_new (GstGLUpload * upload)
223 {
224   struct GLMemoryUpload *mem = g_new0 (struct GLMemoryUpload, 1);
225
226   mem->upload = upload;
227   mem->input_target = GST_GL_TEXTURE_TARGET_NONE;
228   mem->output_target = GST_GL_TEXTURE_TARGET_NONE;
229
230   return mem;
231 }
232
233 static GstCaps *
234 _gl_memory_upload_transform_caps (gpointer impl, GstGLContext * context,
235     GstPadDirection direction, GstCaps * caps)
236 {
237   struct GLMemoryUpload *upload = impl;
238   GstCapsFeatures *passthrough =
239       gst_caps_features_from_string
240       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
241   GstCaps *ret;
242
243   ret =
244       _set_caps_features_with_passthrough (caps,
245       GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
246
247   gst_caps_features_free (passthrough);
248
249   if (direction == GST_PAD_SINK) {
250     GstCaps *tmp;
251     GstGLTextureTarget target_mask;
252
253     if (upload->input_target != GST_GL_TEXTURE_TARGET_NONE) {
254       target_mask = 1 << upload->input_target;
255     } else {
256       target_mask = 1 << GST_GL_TEXTURE_TARGET_2D |
257           1 << GST_GL_TEXTURE_TARGET_RECTANGLE |
258           1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
259     }
260
261     tmp = _caps_intersect_texture_target (ret, target_mask);
262     gst_caps_unref (ret);
263     ret = tmp;
264   } else {
265     gint i, n;
266
267     n = gst_caps_get_size (ret);
268     for (i = 0; i < n; i++) {
269       GstStructure *s = gst_caps_get_structure (ret, i);
270
271       gst_structure_remove_fields (s, "texture-target", NULL);
272     }
273   }
274
275   return ret;
276 }
277
278 static gboolean
279 _gl_memory_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
280     GstCaps * out_caps)
281 {
282   struct GLMemoryUpload *upload = impl;
283   GstCapsFeatures *features;
284   int i;
285
286   features = gst_caps_get_features (out_caps, 0);
287   if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
288     return FALSE;
289
290   features = gst_caps_get_features (in_caps, 0);
291   if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)
292       && !gst_caps_features_contains (features,
293           GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY))
294     return FALSE;
295
296   if (buffer) {
297     GstVideoInfo *in_info = &upload->upload->priv->in_info;
298     guint expected_memories = GST_VIDEO_INFO_N_PLANES (in_info);
299
300     /* Support stereo views for separated multiview mode */
301     if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
302         GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
303       expected_memories *= GST_VIDEO_INFO_VIEWS (in_info);
304
305     if (gst_buffer_n_memory (buffer) != expected_memories)
306       return FALSE;
307
308     for (i = 0; i < expected_memories; i++) {
309       GstMemory *mem = gst_buffer_peek_memory (buffer, i);
310
311       if (!gst_is_gl_memory (mem))
312         return FALSE;
313     }
314   }
315
316   return TRUE;
317 }
318
319 static void
320 _gl_memory_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
321     GstQuery * query)
322 {
323   struct GLMemoryUpload *upload = impl;
324   GstBufferPool *pool = NULL;
325   guint n_pools, i;
326   GstCaps *caps;
327   GstCapsFeatures *features;
328
329   gst_query_parse_allocation (query, &caps, NULL);
330   if (caps == NULL)
331     goto invalid_caps;
332   features = gst_caps_get_features (caps, 0);
333
334   /* Only offer our custom allocator if that type of memory was negotiated. */
335   if (gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
336     GstAllocator *allocator;
337     GstAllocationParams params;
338     gst_allocation_params_init (&params);
339
340     allocator =
341         GST_ALLOCATOR (gst_gl_memory_allocator_get_default (upload->
342             upload->context));
343     gst_query_add_allocation_param (query, allocator, &params);
344     gst_object_unref (allocator);
345
346 #if GST_GL_HAVE_PLATFORM_EGL
347     if (upload->upload->context
348         && gst_gl_context_get_gl_platform (upload->upload->context) ==
349         GST_GL_PLATFORM_EGL) {
350       allocator =
351           GST_ALLOCATOR (gst_allocator_find (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
352       gst_query_add_allocation_param (query, allocator, &params);
353       gst_object_unref (allocator);
354     }
355 #endif
356   }
357
358   n_pools = gst_query_get_n_allocation_pools (query);
359   for (i = 0; i < n_pools; i++) {
360     gst_query_parse_nth_allocation_pool (query, i, &pool, NULL, NULL, NULL);
361     if (!GST_IS_GL_BUFFER_POOL (pool)) {
362       gst_object_unref (pool);
363       pool = NULL;
364     }
365   }
366
367   if (!pool) {
368     GstStructure *config;
369     GstVideoInfo info;
370     gsize size;
371
372
373     if (!gst_video_info_from_caps (&info, caps))
374       goto invalid_caps;
375
376     pool = gst_gl_buffer_pool_new (upload->upload->context);
377     config = gst_buffer_pool_get_config (pool);
378
379     /* the normal size of a frame */
380     size = info.size;
381     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
382     gst_buffer_pool_config_add_option (config,
383         GST_BUFFER_POOL_OPTION_GL_SYNC_META);
384     if (upload->upload->priv->out_caps) {
385       GstGLTextureTarget target;
386       const gchar *target_pool_option_str;
387
388       target =
389           _caps_get_texture_target (upload->upload->priv->out_caps,
390           GST_GL_TEXTURE_TARGET_2D);
391       target_pool_option_str =
392           gst_gl_texture_target_to_buffer_pool_option (target);
393       gst_buffer_pool_config_add_option (config, target_pool_option_str);
394     }
395
396     if (!gst_buffer_pool_set_config (pool, config)) {
397       gst_object_unref (pool);
398       goto config_failed;
399     }
400
401     gst_query_add_allocation_pool (query, pool, size, 1, 0);
402   }
403
404   if (pool)
405     gst_object_unref (pool);
406
407   return;
408
409 invalid_caps:
410   {
411     GST_WARNING_OBJECT (upload->upload, "invalid caps specified");
412     return;
413   }
414 config_failed:
415   {
416     GST_WARNING_OBJECT (upload->upload, "failed setting config");
417     return;
418   }
419 }
420
421 static GstGLUploadReturn
422 _gl_memory_upload_perform (gpointer impl, GstBuffer * buffer,
423     GstBuffer ** outbuf)
424 {
425   struct GLMemoryUpload *upload = impl;
426   GstGLMemory *gl_mem;
427   int i, n;
428
429   n = gst_buffer_n_memory (buffer);
430   for (i = 0; i < n; i++) {
431     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
432
433     gl_mem = (GstGLMemory *) mem;
434     if (!gst_gl_context_can_share (upload->upload->context,
435             gl_mem->mem.context))
436       return GST_GL_UPLOAD_UNSHARED_GL_CONTEXT;
437
438     if (upload->output_target == GST_GL_TEXTURE_TARGET_NONE &&
439         upload->upload->priv->out_caps) {
440       upload->output_target =
441           _caps_get_texture_target (upload->upload->priv->out_caps,
442           GST_GL_TEXTURE_TARGET_NONE);
443     }
444
445     /* always track the last input texture target so ::transform_caps() can
446      * use it to build the output caps */
447     upload->input_target = gl_mem->tex_target;
448     if (upload->output_target != gl_mem->tex_target) {
449       *outbuf = NULL;
450       return GST_GL_UPLOAD_RECONFIGURE;
451     }
452
453     if (gst_is_gl_memory_pbo (mem))
454       gst_gl_memory_pbo_upload_transfer ((GstGLMemoryPBO *) mem);
455   }
456
457   *outbuf = gst_buffer_ref (buffer);
458
459   return GST_GL_UPLOAD_DONE;
460 }
461
462 static void
463 _gl_memory_upload_free (gpointer impl)
464 {
465   g_free (impl);
466 }
467
468
469 static GstStaticCaps _gl_memory_upload_caps =
470 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
471     (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, GST_GL_MEMORY_VIDEO_FORMATS_STR));
472
473 static const UploadMethod _gl_memory_upload = {
474   "GLMemory",
475   METHOD_FLAG_CAN_SHARE_CONTEXT,
476   &_gl_memory_upload_caps,
477   &_gl_memory_upload_new,
478   &_gl_memory_upload_transform_caps,
479   &_gl_memory_upload_accept,
480   &_gl_memory_upload_propose_allocation,
481   &_gl_memory_upload_perform,
482   &_gl_memory_upload_free
483 };
484
485 #if GST_GL_HAVE_DMABUF
486 struct DmabufUpload
487 {
488   GstGLUpload *upload;
489
490   GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES];
491   GstBuffer *outbuf;
492   GstGLVideoAllocationParams *params;
493   guint n_mem;
494
495   gboolean direct;
496   GstVideoInfo out_info;
497   /* only used for pointer comparision */
498   gpointer out_caps;
499 };
500
501 static GstStaticCaps _dma_buf_upload_caps =
502     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
503     (GST_CAPS_FEATURE_MEMORY_DMABUF,
504         GST_GL_MEMORY_VIDEO_FORMATS_STR) ";"
505     GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
506
507 static gpointer
508 _dma_buf_upload_new (GstGLUpload * upload)
509 {
510   struct DmabufUpload *dmabuf = g_new0 (struct DmabufUpload, 1);
511   dmabuf->upload = upload;
512   return dmabuf;
513 }
514
515 static GstCaps *
516 _dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
517     GstPadDirection direction, GstCaps * caps)
518 {
519   GstCapsFeatures *passthrough =
520       gst_caps_features_from_string
521       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
522   GstCaps *ret;
523
524   if (context) {
525     /* Don't propose DMABuf caps feature unless it can be supported */
526     if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
527       return NULL;
528
529     if (!gst_gl_context_check_feature (context, "EGL_KHR_image_base"))
530       return NULL;
531   }
532
533   if (direction == GST_PAD_SINK) {
534     GstCaps *tmp;
535
536     ret =
537         _set_caps_features_with_passthrough (caps,
538         GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
539
540     tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
541     gst_caps_unref (ret);
542     ret = tmp;
543   } else {
544     gint i, n;
545     GstCaps *tmp;
546
547     ret =
548         _set_caps_features_with_passthrough (caps,
549         GST_CAPS_FEATURE_MEMORY_DMABUF, passthrough);
550     tmp =
551         _set_caps_features_with_passthrough (caps,
552         GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
553     gst_caps_append (ret, tmp);
554
555
556     n = gst_caps_get_size (ret);
557     for (i = 0; i < n; i++) {
558       GstStructure *s = gst_caps_get_structure (ret, i);
559
560       gst_structure_remove_fields (s, "texture-target", NULL);
561     }
562   }
563
564   gst_caps_features_free (passthrough);
565
566   return ret;
567 }
568
569 static GQuark
570 _eglimage_quark (gint plane)
571 {
572   static GQuark quark[5] = { 0 };
573   static const gchar *quark_str[] = {
574     "GstGLDMABufEGLImage0",
575     "GstGLDMABufEGLImage1",
576     "GstGLDMABufEGLImage2",
577     "GstGLDMABufEGLImage3",
578     "GstGLDMABufEGLImage",
579   };
580
581   if (!quark[plane])
582     quark[plane] = g_quark_from_static_string (quark_str[plane]);
583
584   return quark[plane];
585 }
586
587 static GstEGLImage *
588 _get_cached_eglimage (GstMemory * mem, gint plane)
589 {
590   return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
591       _eglimage_quark (plane));
592 }
593
594 static void
595 _set_cached_eglimage (GstMemory * mem, GstEGLImage * eglimage, gint plane)
596 {
597   return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
598       _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref);
599 }
600
601 static gboolean
602 _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
603     GstCaps * out_caps)
604 {
605   struct DmabufUpload *dmabuf = impl;
606   GstVideoInfo *in_info = &dmabuf->upload->priv->in_info;
607   GstVideoInfo *out_info = in_info;
608   guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
609   GstVideoMeta *meta;
610   guint n_mem;
611   GstMemory *mems[GST_VIDEO_MAX_PLANES];
612   gsize offset[GST_VIDEO_MAX_PLANES];
613   gint fd[GST_VIDEO_MAX_PLANES];
614   guint i;
615
616   n_mem = gst_buffer_n_memory (buffer);
617   meta = gst_buffer_get_video_meta (buffer);
618
619   /* dmabuf upload is only supported with EGL contexts. */
620   if (gst_gl_context_get_gl_platform (dmabuf->upload->context) !=
621       GST_GL_PLATFORM_EGL)
622     return FALSE;
623
624   if (!gst_gl_context_check_feature (dmabuf->upload->context,
625           "EGL_KHR_image_base"))
626     return FALSE;
627
628   /* This will eliminate most non-dmabuf out there */
629   if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0)))
630     return FALSE;
631
632   /* We cannot have multiple dmabuf per plane */
633   if (n_mem > n_planes)
634     return FALSE;
635
636   /* Update video info based on video meta */
637   if (meta) {
638     in_info->width = meta->width;
639     in_info->height = meta->height;
640
641     for (i = 0; i < meta->n_planes; i++) {
642       in_info->offset[i] = meta->offset[i];
643       in_info->stride[i] = meta->stride[i];
644     }
645   }
646
647   if (dmabuf->direct) {
648     if (out_caps != dmabuf->out_caps) {
649       dmabuf->out_caps = out_caps;
650       if (!gst_video_info_from_caps (&dmabuf->out_info, out_caps))
651         return FALSE;
652     }
653     out_info = &dmabuf->out_info;
654   }
655
656   if (dmabuf->params)
657     gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
658   if (!(dmabuf->params =
659           gst_gl_video_allocation_params_new_wrapped_gl_handle (dmabuf->
660               upload->context, NULL, out_info, -1, NULL,
661               GST_GL_TEXTURE_TARGET_2D, 0, NULL, NULL, NULL)))
662     return FALSE;
663
664   /* Find and validate all memories */
665   for (i = 0; i < n_planes; i++) {
666     guint plane_size;
667     guint length;
668     guint mem_idx;
669     gsize mem_skip;
670
671     plane_size = gst_gl_get_plane_data_size (in_info, NULL, i);
672
673     if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size,
674             &mem_idx, &length, &mem_skip))
675       return FALSE;
676
677     /* We can't have more then one dmabuf per plane */
678     if (length != 1)
679       return FALSE;
680
681     mems[i] = gst_buffer_peek_memory (buffer, mem_idx);
682
683     /* And all memory found must be dmabuf */
684     if (!gst_is_dmabuf_memory (mems[i]))
685       return FALSE;
686
687     offset[i] = mems[i]->offset + mem_skip;
688     fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
689   }
690
691   if (dmabuf->direct)
692     dmabuf->n_mem = 1;
693   else
694     dmabuf->n_mem = n_planes;
695
696   /* Now create an EGLImage for each dmabufs */
697   for (i = 0; i < dmabuf->n_mem; i++) {
698     gint cache_id = dmabuf->direct ? 4 : i;
699
700     /* check if one is cached */
701     dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], cache_id);
702     if (dmabuf->eglimage[i])
703       continue;
704
705     /* otherwise create one and cache it */
706     if (dmabuf->direct)
707       dmabuf->eglimage[i] =
708           gst_egl_image_from_dmabuf_direct (dmabuf->upload->context, fd, offset,
709           in_info);
710     else
711       dmabuf->eglimage[i] = gst_egl_image_from_dmabuf (dmabuf->upload->context,
712           fd[i], in_info, i, offset[i]);
713
714     if (!dmabuf->eglimage[i])
715       return FALSE;
716
717     _set_cached_eglimage (mems[i], dmabuf->eglimage[i], cache_id);
718   }
719
720   return TRUE;
721 }
722
723 static void
724 _dma_buf_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
725     GstQuery * query)
726 {
727   /* nothing to do for now. */
728 }
729
730 static void
731 _dma_buf_upload_perform_gl_thread (GstGLContext * context,
732     struct DmabufUpload *dmabuf)
733 {
734   GstGLMemoryAllocator *allocator;
735
736   allocator =
737       GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
738       (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
739
740   /* FIXME: buffer pool */
741   dmabuf->outbuf = gst_buffer_new ();
742   gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params, NULL,
743       (gpointer *) dmabuf->eglimage, dmabuf->n_mem);
744   gst_object_unref (allocator);
745 }
746
747 static GstGLUploadReturn
748 _dma_buf_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
749 {
750   struct DmabufUpload *dmabuf = impl;
751
752   gst_gl_context_thread_add (dmabuf->upload->context,
753       (GstGLContextThreadFunc) _dma_buf_upload_perform_gl_thread, dmabuf);
754
755   if (!dmabuf->outbuf)
756     return GST_GL_UPLOAD_ERROR;
757
758   gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer);
759
760   *outbuf = dmabuf->outbuf;
761   dmabuf->outbuf = NULL;
762
763   return GST_GL_UPLOAD_DONE;
764 }
765
766 static void
767 _dma_buf_upload_free (gpointer impl)
768 {
769   struct DmabufUpload *dmabuf = impl;
770
771   if (dmabuf->params)
772     gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
773
774   g_free (impl);
775 }
776
777 static const UploadMethod _dma_buf_upload = {
778   "Dmabuf",
779   0,
780   &_dma_buf_upload_caps,
781   &_dma_buf_upload_new,
782   &_dma_buf_upload_transform_caps,
783   &_dma_buf_upload_accept,
784   &_dma_buf_upload_propose_allocation,
785   &_dma_buf_upload_perform,
786   &_dma_buf_upload_free
787 };
788
789 /* a variant of the DMABuf uploader that relies on HW color convertion instead
790  * of shaders */
791
792 static gpointer
793 _direct_dma_buf_upload_new (GstGLUpload * upload)
794 {
795   struct DmabufUpload *dmabuf = _dma_buf_upload_new (upload);
796   dmabuf->direct = TRUE;
797   gst_video_info_init (&dmabuf->out_info);
798   return dmabuf;
799 }
800
801 static GstCaps *
802 _direct_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
803     GstPadDirection direction, GstCaps * caps)
804 {
805   GstCapsFeatures *passthrough =
806       gst_caps_features_from_string
807       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
808   GstCaps *ret;
809
810   if (direction == GST_PAD_SINK) {
811     gint i, n;
812     GstCaps *tmp;
813
814     ret =
815         _set_caps_features_with_passthrough (caps,
816         GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
817
818     gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
819
820     n = gst_caps_get_size (ret);
821     for (i = 0; i < n; i++) {
822       GstStructure *s = gst_caps_get_structure (ret, i);
823
824       gst_structure_remove_fields (s, "chroma-site", NULL);
825       gst_structure_remove_fields (s, "colorimetry", NULL);
826     }
827     tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
828     gst_caps_unref (ret);
829     ret = tmp;
830   } else {
831     gint i, n;
832     GstCaps *tmp;
833     GValue formats = G_VALUE_INIT;
834     gchar *format_str = g_strdup (GST_GL_MEMORY_VIDEO_FORMATS_STR);
835
836     ret =
837         _set_caps_features_with_passthrough (caps,
838         GST_CAPS_FEATURE_MEMORY_DMABUF, passthrough);
839     tmp =
840         _set_caps_features_with_passthrough (caps,
841         GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
842     gst_caps_append (ret, tmp);
843
844     g_value_init (&formats, GST_TYPE_LIST);
845     gst_value_deserialize (&formats, format_str);
846     gst_caps_set_value (ret, "format", &formats);
847     g_free (format_str);
848     g_value_unset (&formats);
849
850     n = gst_caps_get_size (ret);
851     for (i = 0; i < n; i++) {
852       GstStructure *s = gst_caps_get_structure (ret, i);
853
854       gst_structure_remove_fields (s, "texture-target", NULL);
855     }
856   }
857
858   gst_caps_features_free (passthrough);
859
860   return ret;
861 }
862
863 static const UploadMethod _direct_dma_buf_upload = {
864   "DirectDmabuf",
865   0,
866   &_dma_buf_upload_caps,
867   &_direct_dma_buf_upload_new,
868   &_direct_dma_buf_upload_transform_caps,
869   &_dma_buf_upload_accept,
870   &_dma_buf_upload_propose_allocation,
871   &_dma_buf_upload_perform,
872   &_dma_buf_upload_free
873 };
874
875 #endif /* GST_GL_HAVE_DMABUF */
876
877 struct GLUploadMeta
878 {
879   GstGLUpload *upload;
880
881   gboolean result;
882   GstVideoGLTextureUploadMeta *meta;
883   guint texture_ids[GST_GL_UPLOAD_MAX_PLANES];
884   GstBufferPool *pool;
885 };
886
887 static gpointer
888 _upload_meta_upload_new (GstGLUpload * upload)
889 {
890   struct GLUploadMeta *meta = g_new0 (struct GLUploadMeta, 1);
891
892   meta->upload = upload;
893   meta->pool = NULL;
894
895   return meta;
896 }
897
898 static GstCaps *
899 _upload_meta_upload_transform_caps (gpointer impl, GstGLContext * context,
900     GstPadDirection direction, GstCaps * caps)
901 {
902   GstCapsFeatures *passthrough =
903       gst_caps_features_from_string
904       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
905   GstCaps *ret;
906
907   if (direction == GST_PAD_SINK) {
908     GstCaps *tmp;
909
910     ret =
911         _set_caps_features_with_passthrough (caps,
912         GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
913
914     tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
915     gst_caps_unref (ret);
916     ret = tmp;
917   } else {
918     gint i, n;
919
920     ret =
921         _set_caps_features_with_passthrough (caps,
922         GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, passthrough);
923     gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
924
925     n = gst_caps_get_size (ret);
926     for (i = 0; i < n; i++) {
927       GstStructure *s = gst_caps_get_structure (ret, i);
928
929       gst_structure_remove_fields (s, "texture-target", NULL);
930     }
931   }
932
933   gst_caps_features_free (passthrough);
934
935   return ret;
936 }
937
938 static gboolean
939 _upload_meta_upload_accept (gpointer impl, GstBuffer * buffer,
940     GstCaps * in_caps, GstCaps * out_caps)
941 {
942   struct GLUploadMeta *upload = impl;
943   GstCapsFeatures *features;
944   GstVideoGLTextureUploadMeta *meta;
945   gboolean ret = TRUE;
946   GstStructure *config;
947   gsize size;
948
949   features = gst_caps_get_features (in_caps, 0);
950
951   if (!gst_caps_features_contains (features,
952           GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META))
953     ret = FALSE;
954
955   features = gst_caps_get_features (out_caps, 0);
956   if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
957     ret = FALSE;
958
959   if (!ret)
960     return ret;
961
962   if (upload->pool == NULL)
963     upload->pool = gst_gl_buffer_pool_new (upload->upload->context);
964
965   if (!gst_buffer_pool_is_active (upload->pool)) {
966     config = gst_buffer_pool_get_config (upload->pool);
967
968     size = upload->upload->priv->in_info.size;
969     gst_buffer_pool_config_set_params (config, in_caps, size, 0, 0);
970
971     if (!gst_buffer_pool_set_config (upload->pool, config)) {
972       GST_WARNING_OBJECT (upload->upload, "failed to set bufferpool config");
973       return FALSE;
974     }
975     gst_buffer_pool_set_active (upload->pool, TRUE);
976   }
977
978   if (buffer) {
979     if ((meta = gst_buffer_get_video_gl_texture_upload_meta (buffer)) == NULL)
980       return FALSE;
981
982     if (meta->texture_type[0] != GST_VIDEO_GL_TEXTURE_TYPE_RGBA) {
983       GST_FIXME_OBJECT (upload, "only single rgba texture supported");
984       return FALSE;
985     }
986
987     if (meta->texture_orientation !=
988         GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL) {
989       GST_FIXME_OBJECT (upload, "only x-normal, y-normal textures supported");
990       return FALSE;
991     }
992   }
993
994   return TRUE;
995 }
996
997 static void
998 _upload_meta_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
999     GstQuery * query)
1000 {
1001   struct GLUploadMeta *upload = impl;
1002   GstStructure *gl_context;
1003   gchar *platform, *gl_apis;
1004   gpointer handle;
1005
1006   gl_apis =
1007       gst_gl_api_to_string (gst_gl_context_get_gl_api (upload->upload->
1008           context));
1009   platform =
1010       gst_gl_platform_to_string (gst_gl_context_get_gl_platform (upload->
1011           upload->context));
1012   handle = (gpointer) gst_gl_context_get_gl_context (upload->upload->context);
1013
1014   gl_context =
1015       gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
1016       GST_TYPE_GL_CONTEXT, upload->upload->context, "gst.gl.context.handle",
1017       G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
1018       "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
1019   gst_query_add_allocation_meta (query,
1020       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
1021
1022   g_free (gl_apis);
1023   g_free (platform);
1024   gst_structure_free (gl_context);
1025 }
1026
1027 /*
1028  * Uploads using gst_video_gl_texture_upload_meta_upload().
1029  * i.e. consumer of GstVideoGLTextureUploadMeta
1030  */
1031 static void
1032 _do_upload_with_meta (GstGLContext * context, struct GLUploadMeta *upload)
1033 {
1034   if (!gst_video_gl_texture_upload_meta_upload (upload->meta,
1035           upload->texture_ids)) {
1036     upload->result = FALSE;
1037     return;
1038   }
1039
1040   upload->result = TRUE;
1041 }
1042
1043 static GstGLUploadReturn
1044 _upload_meta_upload_perform (gpointer impl, GstBuffer * buffer,
1045     GstBuffer ** outbuf)
1046 {
1047   struct GLUploadMeta *upload = impl;
1048   int i;
1049   GstVideoInfo *in_info = &upload->upload->priv->in_info;
1050   guint max_planes = GST_VIDEO_INFO_N_PLANES (in_info);
1051
1052   /* Support stereo views for separated multiview mode */
1053   if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
1054       GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
1055     max_planes *= GST_VIDEO_INFO_VIEWS (in_info);
1056
1057   GST_LOG_OBJECT (upload, "Attempting upload with GstVideoGLTextureUploadMeta");
1058
1059   upload->meta = gst_buffer_get_video_gl_texture_upload_meta (buffer);
1060
1061   if (gst_buffer_pool_acquire_buffer (upload->pool, outbuf,
1062           NULL) != GST_FLOW_OK) {
1063     GST_WARNING_OBJECT (upload, "failed to acquire buffer from bufferpool");
1064     return GST_GL_UPLOAD_ERROR;
1065   }
1066
1067   for (i = 0; i < GST_GL_UPLOAD_MAX_PLANES; i++) {
1068     guint tex_id = 0;
1069
1070     if (i < max_planes) {
1071       GstMemory *mem = gst_buffer_peek_memory (*outbuf, i);
1072       tex_id = ((GstGLMemory *) mem)->tex_id;
1073     }
1074
1075     upload->texture_ids[i] = tex_id;
1076   }
1077
1078   GST_LOG ("Uploading with GLTextureUploadMeta with textures "
1079       "%i,%i,%i,%i / %i,%i,%i,%i",
1080       upload->texture_ids[0], upload->texture_ids[1],
1081       upload->texture_ids[2], upload->texture_ids[3],
1082       upload->texture_ids[4], upload->texture_ids[5],
1083       upload->texture_ids[6], upload->texture_ids[7]);
1084
1085   gst_gl_context_thread_add (upload->upload->context,
1086       (GstGLContextThreadFunc) _do_upload_with_meta, upload);
1087
1088   if (!upload->result)
1089     return GST_GL_UPLOAD_ERROR;
1090
1091   return GST_GL_UPLOAD_DONE;
1092 }
1093
1094 static void
1095 _upload_meta_upload_free (gpointer impl)
1096 {
1097   struct GLUploadMeta *upload = impl;
1098
1099   g_return_if_fail (impl != NULL);
1100
1101   if (upload->pool)
1102     gst_object_unref (upload->pool);
1103
1104   g_free (upload);
1105 }
1106
1107 static GstStaticCaps _upload_meta_upload_caps =
1108 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1109     (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA"));
1110
1111 static const UploadMethod _upload_meta_upload = {
1112   "UploadMeta",
1113   METHOD_FLAG_CAN_SHARE_CONTEXT,
1114   &_upload_meta_upload_caps,
1115   &_upload_meta_upload_new,
1116   &_upload_meta_upload_transform_caps,
1117   &_upload_meta_upload_accept,
1118   &_upload_meta_upload_propose_allocation,
1119   &_upload_meta_upload_perform,
1120   &_upload_meta_upload_free
1121 };
1122
1123 struct RawUploadFrame
1124 {
1125   gint ref_count;
1126   GstVideoFrame frame;
1127 };
1128
1129 struct RawUpload
1130 {
1131   GstGLUpload *upload;
1132   struct RawUploadFrame *in_frame;
1133   GstGLVideoAllocationParams *params;
1134 };
1135
1136 static struct RawUploadFrame *
1137 _raw_upload_frame_new (struct RawUpload *raw, GstBuffer * buffer)
1138 {
1139   struct RawUploadFrame *frame;
1140   GstVideoInfo *info;
1141   gint i;
1142
1143   if (!buffer)
1144     return NULL;
1145
1146   frame = g_slice_new (struct RawUploadFrame);
1147   frame->ref_count = 1;
1148
1149   if (!gst_video_frame_map (&frame->frame, &raw->upload->priv->in_info,
1150           buffer, GST_MAP_READ)) {
1151     g_slice_free (struct RawUploadFrame, frame);
1152     return NULL;
1153   }
1154
1155   raw->upload->priv->in_info = frame->frame.info;
1156   info = &raw->upload->priv->in_info;
1157
1158   /* Recalculate the offsets (and size) */
1159   info->size = 0;
1160   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1161     info->offset[i] = info->size;
1162     info->size += gst_gl_get_plane_data_size (info, NULL, i);
1163   }
1164
1165   return frame;
1166 }
1167
1168 static void
1169 _raw_upload_frame_ref (struct RawUploadFrame *frame)
1170 {
1171   g_atomic_int_inc (&frame->ref_count);
1172 }
1173
1174 static void
1175 _raw_upload_frame_unref (struct RawUploadFrame *frame)
1176 {
1177   if (g_atomic_int_dec_and_test (&frame->ref_count)) {
1178     gst_video_frame_unmap (&frame->frame);
1179     g_slice_free (struct RawUploadFrame, frame);
1180   }
1181 }
1182
1183 static gpointer
1184 _raw_data_upload_new (GstGLUpload * upload)
1185 {
1186   struct RawUpload *raw = g_new0 (struct RawUpload, 1);
1187
1188   raw->upload = upload;
1189
1190   return raw;
1191 }
1192
1193 static GstCaps *
1194 _raw_data_upload_transform_caps (gpointer impl, GstGLContext * context,
1195     GstPadDirection direction, GstCaps * caps)
1196 {
1197   GstCapsFeatures *passthrough =
1198       gst_caps_features_from_string
1199       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1200   GstCaps *ret;
1201
1202   if (direction == GST_PAD_SINK) {
1203     GstGLTextureTarget target_mask = 0;
1204     GstCaps *tmp;
1205
1206     ret =
1207         _set_caps_features_with_passthrough (caps,
1208         GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1209
1210     target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D;
1211     target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE;
1212     tmp = _caps_intersect_texture_target (ret, target_mask);
1213     gst_caps_unref (ret);
1214     ret = tmp;
1215   } else {
1216     gint i, n;
1217
1218     ret =
1219         _set_caps_features_with_passthrough (caps,
1220         GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
1221
1222     n = gst_caps_get_size (ret);
1223     for (i = 0; i < n; i++) {
1224       GstStructure *s = gst_caps_get_structure (ret, i);
1225
1226       gst_structure_remove_fields (s, "texture-target", NULL);
1227     }
1228   }
1229
1230   gst_caps_features_free (passthrough);
1231
1232   return ret;
1233 }
1234
1235 static gboolean
1236 _raw_data_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1237     GstCaps * out_caps)
1238 {
1239   struct RawUpload *raw = impl;
1240   GstCapsFeatures *features;
1241
1242   features = gst_caps_get_features (out_caps, 0);
1243   if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1244     return FALSE;
1245
1246   if (raw->in_frame)
1247     _raw_upload_frame_unref (raw->in_frame);
1248   raw->in_frame = _raw_upload_frame_new (raw, buffer);
1249
1250   if (raw->params)
1251     gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1252   if (!(raw->params =
1253           gst_gl_video_allocation_params_new_wrapped_data (raw->upload->context,
1254               NULL, &raw->upload->priv->in_info, -1, NULL,
1255               GST_GL_TEXTURE_TARGET_2D, 0, NULL, raw->in_frame,
1256               (GDestroyNotify) _raw_upload_frame_unref)))
1257     return FALSE;
1258
1259   return (raw->in_frame != NULL);
1260 }
1261
1262 static void
1263 _raw_data_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1264     GstQuery * query)
1265 {
1266   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
1267 }
1268
1269 static GstGLUploadReturn
1270 _raw_data_upload_perform (gpointer impl, GstBuffer * buffer,
1271     GstBuffer ** outbuf)
1272 {
1273   GstGLBaseMemoryAllocator *allocator;
1274   struct RawUpload *raw = impl;
1275   int i;
1276   GstVideoInfo *in_info = &raw->upload->priv->in_info;
1277   guint n_mem = GST_VIDEO_INFO_N_PLANES (in_info);
1278
1279   allocator =
1280       GST_GL_BASE_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_default
1281       (raw->upload->context));
1282
1283   /* FIXME Use a buffer pool to cache the generated textures */
1284   /* FIXME: multiview support with separated left/right frames? */
1285   *outbuf = gst_buffer_new ();
1286   for (i = 0; i < n_mem; i++) {
1287     GstGLBaseMemory *tex;
1288
1289     raw->params->parent.wrapped_data = raw->in_frame->frame.data[i];
1290     raw->params->plane = i;
1291     raw->params->tex_format =
1292         gst_gl_format_from_video_info (raw->upload->context, in_info, i);
1293
1294     tex =
1295         gst_gl_base_memory_alloc (allocator,
1296         (GstGLAllocationParams *) raw->params);
1297     if (!tex) {
1298       gst_buffer_unref (*outbuf);
1299       *outbuf = NULL;
1300       GST_ERROR_OBJECT (raw->upload, "Failed to allocate wrapped texture");
1301       return GST_GL_UPLOAD_ERROR;
1302     }
1303
1304     _raw_upload_frame_ref (raw->in_frame);
1305     gst_buffer_append_memory (*outbuf, (GstMemory *) tex);
1306   }
1307   gst_object_unref (allocator);
1308
1309   _raw_upload_frame_unref (raw->in_frame);
1310   raw->in_frame = NULL;
1311   return GST_GL_UPLOAD_DONE;
1312 }
1313
1314 static void
1315 _raw_data_upload_free (gpointer impl)
1316 {
1317   struct RawUpload *raw = impl;
1318
1319   if (raw->params)
1320     gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1321
1322   g_free (raw);
1323 }
1324
1325 static GstStaticCaps _raw_data_upload_caps =
1326 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
1327
1328 static const UploadMethod _raw_data_upload = {
1329   "Raw Data",
1330   0,
1331   &_raw_data_upload_caps,
1332   &_raw_data_upload_new,
1333   &_raw_data_upload_transform_caps,
1334   &_raw_data_upload_accept,
1335   &_raw_data_upload_propose_allocation,
1336   &_raw_data_upload_perform,
1337   &_raw_data_upload_free
1338 };
1339
1340 #if GST_GL_HAVE_VIV_DIRECTVIV
1341 #ifndef GL_BGRA_EXT
1342 #define GL_BGRA_EXT                                             0x80E1
1343 #endif
1344 #ifndef GL_VIV_YV12
1345 #define GL_VIV_YV12                                             0x8FC0
1346 #endif
1347 #ifndef GL_VIV_NV12
1348 #define GL_VIV_NV12                                             0x8FC1
1349 #endif
1350 #ifndef GL_VIV_YUY2
1351 #define GL_VIV_YUY2                                             0x8FC2
1352 #endif
1353 #ifndef GL_VIV_UYVY
1354 #define GL_VIV_UYVY                                             0x8FC3
1355 #endif
1356 #ifndef GL_VIV_NV21
1357 #define GL_VIV_NV21                                             0x8FC4
1358 #endif
1359 #ifndef GL_VIV_I420
1360 #define GL_VIV_I420                                             0x8FC5
1361 #endif
1362
1363 struct DirectVIVUpload
1364 {
1365   GstGLUpload *upload;
1366
1367   GstGLVideoAllocationParams *params;
1368   GstBuffer *inbuf, *outbuf;
1369   void (*TexDirectVIVMap) (GLenum Target, GLsizei Width, GLsizei Height,
1370       GLenum Format, GLvoid ** Logical, const GLuint * Physical);
1371   void (*TexDirectInvalidateVIV) (GLenum Target);
1372   gboolean loaded_functions;
1373 };
1374
1375 #define GST_GL_DIRECTVIV_FORMAT "{RGBA, I420, YV12, NV12, NV21, YUY2, UYVY, BGRA, RGB16}"
1376
1377 static GstStaticCaps _directviv_upload_caps =
1378 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DIRECTVIV_FORMAT));
1379
1380 static gpointer
1381 _directviv_upload_new (GstGLUpload * upload)
1382 {
1383   struct DirectVIVUpload *directviv = g_new0 (struct DirectVIVUpload, 1);
1384   directviv->upload = upload;
1385   directviv->loaded_functions = FALSE;
1386
1387   return directviv;
1388 }
1389
1390 static GstCaps *
1391 _directviv_upload_transform_caps (gpointer impl, GstGLContext * context,
1392     GstPadDirection direction, GstCaps * caps)
1393 {
1394   GstCapsFeatures *passthrough =
1395       gst_caps_features_from_string
1396       (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1397   GstCaps *ret;
1398
1399   if (direction == GST_PAD_SINK) {
1400     GstCaps *tmp;
1401
1402     ret =
1403         _set_caps_features_with_passthrough (caps,
1404         GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1405
1406     gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
1407     tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
1408     gst_caps_unref (ret);
1409     ret = tmp;
1410   } else {
1411     GstCaps *tmp;
1412     tmp = gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1413         (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, GST_GL_DIRECTVIV_FORMAT));
1414     ret =
1415         _set_caps_features_with_passthrough (tmp,
1416         GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
1417     gst_caps_unref (tmp);
1418   }
1419
1420   gst_caps_features_free (passthrough);
1421   return ret;
1422 }
1423
1424
1425 static void
1426 _directviv_upload_load_functions_gl_thread (GstGLContext * context,
1427     struct DirectVIVUpload *directviv)
1428 {
1429   directviv->TexDirectVIVMap =
1430       gst_gl_context_get_proc_address (context, "glTexDirectVIVMap");
1431   directviv->TexDirectInvalidateVIV =
1432       gst_gl_context_get_proc_address (context, "glTexDirectInvalidateVIV");
1433 }
1434
1435 static gboolean
1436 _directviv_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1437     GstCaps * out_caps)
1438 {
1439   struct DirectVIVUpload *directviv = impl;
1440   GstCapsFeatures *features;
1441   guint n_mem;
1442   GstMemory *mem;
1443
1444   if (!directviv->loaded_functions && (!directviv->TexDirectInvalidateVIV ||
1445           !directviv->TexDirectVIVMap)) {
1446     gst_gl_context_thread_add (directviv->upload->context,
1447         (GstGLContextThreadFunc) _directviv_upload_load_functions_gl_thread,
1448         directviv);
1449     directviv->loaded_functions = TRUE;
1450   }
1451   if (!directviv->TexDirectInvalidateVIV || !directviv->TexDirectVIVMap)
1452     return FALSE;
1453
1454   features = gst_caps_get_features (out_caps, 0);
1455   if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1456     return FALSE;
1457
1458   if (directviv->params)
1459     gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1460   if (!(directviv->params =
1461           gst_gl_video_allocation_params_new (directviv->upload->context, NULL,
1462               &directviv->upload->priv->out_info, -1, NULL,
1463               GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA)))
1464     return FALSE;
1465
1466   /* We only support a single memory per buffer at this point */
1467   n_mem = gst_buffer_n_memory (buffer);
1468   if (n_mem == 1) {
1469     mem = gst_buffer_peek_memory (buffer, 0);
1470   } else {
1471     mem = NULL;
1472   }
1473
1474   return n_mem == 1 && mem && gst_is_phys_memory (mem);
1475 }
1476
1477 static void
1478 _directviv_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1479     GstQuery * query)
1480 {
1481 }
1482
1483 static GLenum
1484 _directviv_upload_video_format_to_gl_format (GstVideoFormat format)
1485 {
1486   switch (format) {
1487     case GST_VIDEO_FORMAT_I420:
1488       return GL_VIV_I420;
1489     case GST_VIDEO_FORMAT_YV12:
1490       return GL_VIV_YV12;
1491     case GST_VIDEO_FORMAT_NV12:
1492       return GL_VIV_NV12;
1493     case GST_VIDEO_FORMAT_NV21:
1494       return GL_VIV_NV21;
1495     case GST_VIDEO_FORMAT_YUY2:
1496       return GL_VIV_YUY2;
1497     case GST_VIDEO_FORMAT_UYVY:
1498       return GL_VIV_UYVY;
1499     case GST_VIDEO_FORMAT_RGB16:
1500       return GL_RGB565;
1501     case GST_VIDEO_FORMAT_RGBA:
1502       return GL_RGBA;
1503     case GST_VIDEO_FORMAT_BGRA:
1504       return GL_BGRA_EXT;
1505     case GST_VIDEO_FORMAT_RGBx:
1506       return GL_RGBA;
1507     case GST_VIDEO_FORMAT_BGRx:
1508       return GL_BGRA_EXT;
1509     default:
1510       return 0;
1511   }
1512 }
1513
1514 typedef struct
1515 {
1516   GstBuffer *buffer;
1517   GstMemory *memory;
1518   GstMapInfo map;
1519   guintptr phys_addr;
1520 } DirectVIVUnmapData;
1521
1522 static void
1523 _directviv_memory_unmap (DirectVIVUnmapData * data)
1524 {
1525   gst_memory_unmap (data->memory, &data->map);
1526   gst_memory_unref (data->memory);
1527   gst_buffer_unref (data->buffer);
1528   g_free (data);
1529 }
1530
1531 static void
1532 _directviv_upload_perform_gl_thread (GstGLContext * context,
1533     struct DirectVIVUpload *directviv)
1534 {
1535   static GQuark directviv_unmap_quark = 0;
1536   GstGLMemoryAllocator *allocator;
1537   GstMemory *in_mem;
1538   GstGLMemory *out_gl_mem;
1539   GstVideoInfo *in_info;
1540   DirectVIVUnmapData *unmap_data;
1541   GstVideoMeta *vmeta;
1542   gint width, height, gl_format;
1543   const GstGLFuncs *gl;
1544
1545   if (!directviv_unmap_quark)
1546     directviv_unmap_quark = g_quark_from_static_string ("GstGLDirectVIVUnmap");
1547
1548   gl = context->gl_vtable;
1549
1550   g_assert (gst_buffer_n_memory (directviv->inbuf) == 1);
1551   in_info = &directviv->upload->priv->in_info;
1552   in_mem = gst_buffer_peek_memory (directviv->inbuf, 0);
1553   unmap_data = g_new0 (DirectVIVUnmapData, 1);
1554   if (!gst_memory_map (in_mem, &unmap_data->map, GST_MAP_READ)) {
1555     g_free (unmap_data);
1556     return;
1557   }
1558   unmap_data->phys_addr = gst_phys_memory_get_phys_addr (in_mem);
1559   if (!unmap_data->phys_addr) {
1560     gst_memory_unmap (in_mem, &unmap_data->map);
1561     g_free (unmap_data);
1562     return;
1563   }
1564   unmap_data->memory = gst_memory_ref (in_mem);
1565   unmap_data->buffer = gst_buffer_ref (directviv->inbuf);
1566
1567   allocator =
1568       GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
1569       (GST_GL_MEMORY_PBO_ALLOCATOR_NAME));
1570
1571   /* FIXME: buffer pool */
1572   directviv->outbuf = gst_buffer_new ();
1573   gst_gl_memory_setup_buffer (allocator, directviv->outbuf, directviv->params,
1574       NULL, NULL, 0);
1575   gst_object_unref (allocator);
1576
1577   out_gl_mem = (GstGLMemory *) gst_buffer_peek_memory (directviv->outbuf, 0);
1578
1579   /* Need to keep the input memory and buffer mapped and valid until
1580    * the GL memory is not used anymore */
1581   gst_mini_object_set_qdata ((GstMiniObject *) out_gl_mem,
1582       directviv_unmap_quark, unmap_data,
1583       (GDestroyNotify) _directviv_memory_unmap);
1584   gst_buffer_add_parent_buffer_meta (directviv->outbuf, directviv->inbuf);
1585
1586   /* width/height need to compensate for stride/padding */
1587   vmeta = gst_buffer_get_video_meta (directviv->inbuf);
1588   if (vmeta) {
1589     width = vmeta->stride[0];
1590     if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1591       height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1592     else
1593       height = vmeta->offset[1] / width;
1594   } else {
1595     width = GST_VIDEO_INFO_PLANE_STRIDE (in_info, 0);
1596     if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1597       height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1598     else
1599       height = GST_VIDEO_INFO_PLANE_OFFSET (in_info, 1) / width;
1600   }
1601   width /= GST_VIDEO_INFO_COMP_PSTRIDE (in_info, 0);
1602
1603   gl_format =
1604       _directviv_upload_video_format_to_gl_format (GST_VIDEO_INFO_FORMAT
1605       (in_info));
1606
1607   gl->BindTexture (GL_TEXTURE_2D, out_gl_mem->tex_id);
1608   directviv->TexDirectVIVMap (GL_TEXTURE_2D, width, height,
1609       gl_format, (void **) &unmap_data->map.data, &unmap_data->phys_addr);
1610   directviv->TexDirectInvalidateVIV (GL_TEXTURE_2D);
1611 }
1612
1613 static GstGLUploadReturn
1614 _directviv_upload_perform (gpointer impl, GstBuffer * buffer,
1615     GstBuffer ** outbuf)
1616 {
1617   struct DirectVIVUpload *directviv = impl;
1618
1619   directviv->inbuf = buffer;
1620   directviv->outbuf = NULL;
1621   gst_gl_context_thread_add (directviv->upload->context,
1622       (GstGLContextThreadFunc) _directviv_upload_perform_gl_thread, directviv);
1623   directviv->inbuf = NULL;
1624
1625   if (!directviv->outbuf)
1626     return GST_GL_UPLOAD_ERROR;
1627
1628   *outbuf = directviv->outbuf;
1629   directviv->outbuf = NULL;
1630
1631   return GST_GL_UPLOAD_DONE;
1632 }
1633
1634 static void
1635 _directviv_upload_free (gpointer impl)
1636 {
1637   struct DirectVIVUpload *directviv = impl;
1638
1639   if (directviv->params)
1640     gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1641
1642   g_free (impl);
1643 }
1644
1645 static const UploadMethod _directviv_upload = {
1646   "DirectVIV",
1647   0,
1648   &_directviv_upload_caps,
1649   &_directviv_upload_new,
1650   &_directviv_upload_transform_caps,
1651   &_directviv_upload_accept,
1652   &_directviv_upload_propose_allocation,
1653   &_directviv_upload_perform,
1654   &_directviv_upload_free
1655 };
1656
1657 #endif /* GST_GL_HAVE_VIV_DIRECTVIV */
1658
1659 static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
1660 #if GST_GL_HAVE_DMABUF
1661   &_direct_dma_buf_upload,
1662   &_dma_buf_upload,
1663 #endif
1664 #if GST_GL_HAVE_VIV_DIRECTVIV
1665   &_directviv_upload,
1666 #endif
1667   &_upload_meta_upload, &_raw_data_upload
1668 };
1669
1670 static GMutex upload_global_lock;
1671
1672 GstCaps *
1673 gst_gl_upload_get_input_template_caps (void)
1674 {
1675   GstCaps *ret = NULL;
1676   gint i;
1677
1678   g_mutex_lock (&upload_global_lock);
1679
1680   /* FIXME: cache this and invalidate on changes to upload_methods */
1681   for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
1682     GstCaps *template =
1683         gst_static_caps_get (upload_methods[i]->input_template_caps);
1684     ret = ret == NULL ? template : gst_caps_merge (ret, template);
1685   }
1686
1687   ret = gst_caps_simplify (ret);
1688   ret = gst_gl_overlay_compositor_add_caps (ret);
1689   g_mutex_unlock (&upload_global_lock);
1690
1691   return ret;
1692 }
1693
1694 static void
1695 gst_gl_upload_class_init (GstGLUploadClass * klass)
1696 {
1697   G_OBJECT_CLASS (klass)->finalize = gst_gl_upload_finalize;
1698 }
1699
1700 static void
1701 gst_gl_upload_init (GstGLUpload * upload)
1702 {
1703   upload->priv = gst_gl_upload_get_instance_private (upload);
1704 }
1705
1706 /**
1707  * gst_gl_upload_new:
1708  * @context: a #GstGLContext
1709  *
1710  * Returns: (transfer full): a new #GstGLUpload object
1711  */
1712 GstGLUpload *
1713 gst_gl_upload_new (GstGLContext * context)
1714 {
1715   GstGLUpload *upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL);
1716   gint i, n;
1717
1718   gst_object_ref_sink (upload);
1719
1720   if (context)
1721     gst_gl_upload_set_context (upload, context);
1722   else
1723     upload->context = NULL;
1724
1725   n = G_N_ELEMENTS (upload_methods);
1726   upload->priv->upload_impl = g_malloc (sizeof (gpointer) * n);
1727   for (i = 0; i < n; i++) {
1728     upload->priv->upload_impl[i] = upload_methods[i]->new (upload);
1729   }
1730
1731   GST_DEBUG_OBJECT (upload, "Created new GLUpload for context %" GST_PTR_FORMAT,
1732       context);
1733
1734   return upload;
1735 }
1736
1737 void
1738 gst_gl_upload_set_context (GstGLUpload * upload, GstGLContext * context)
1739 {
1740   g_return_if_fail (upload != NULL);
1741
1742   gst_object_replace ((GstObject **) & upload->context, (GstObject *) context);
1743 }
1744
1745 static void
1746 gst_gl_upload_finalize (GObject * object)
1747 {
1748   GstGLUpload *upload;
1749   gint i, n;
1750
1751   upload = GST_GL_UPLOAD (object);
1752
1753   upload->priv->method_i = 0;
1754
1755   if (upload->context) {
1756     gst_object_unref (upload->context);
1757     upload->context = NULL;
1758   }
1759
1760   if (upload->priv->in_caps) {
1761     gst_caps_unref (upload->priv->in_caps);
1762     upload->priv->in_caps = NULL;
1763   }
1764
1765   if (upload->priv->out_caps) {
1766     gst_caps_unref (upload->priv->out_caps);
1767     upload->priv->out_caps = NULL;
1768   }
1769
1770   n = G_N_ELEMENTS (upload_methods);
1771   for (i = 0; i < n; i++) {
1772     if (upload->priv->upload_impl[i])
1773       upload_methods[i]->free (upload->priv->upload_impl[i]);
1774   }
1775   g_free (upload->priv->upload_impl);
1776
1777   G_OBJECT_CLASS (gst_gl_upload_parent_class)->finalize (object);
1778 }
1779
1780 GstCaps *
1781 gst_gl_upload_transform_caps (GstGLUpload * upload, GstGLContext * context,
1782     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1783 {
1784   GstCaps *result, *tmp;
1785   gint i;
1786
1787   if (upload->priv->method)
1788     return upload->priv->method->transform_caps (upload->priv->method_impl,
1789         context, direction, caps);
1790
1791   tmp = gst_caps_new_empty ();
1792
1793   for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
1794     GstCaps *tmp2;
1795
1796     tmp2 =
1797         upload_methods[i]->transform_caps (upload->priv->upload_impl[i],
1798         context, direction, caps);
1799
1800     if (tmp2)
1801       tmp = gst_caps_merge (tmp, tmp2);
1802   }
1803
1804   if (filter) {
1805     result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1806     gst_caps_unref (tmp);
1807   } else {
1808     result = tmp;
1809   }
1810
1811   return result;
1812 }
1813
1814 /**
1815  * gst_gl_upload_propose_allocation:
1816  * @upload: a #GstGLUpload
1817  * @decide_query: (allow-none): a #GstQuery from a decide allocation
1818  * @query: the proposed allocation query
1819  *
1820  * Adds the required allocation parameters to support uploading.
1821  */
1822 void
1823 gst_gl_upload_propose_allocation (GstGLUpload * upload, GstQuery * decide_query,
1824     GstQuery * query)
1825 {
1826   gint i;
1827
1828   for (i = 0; i < G_N_ELEMENTS (upload_methods); i++)
1829     upload_methods[i]->propose_allocation (upload->priv->upload_impl[i],
1830         decide_query, query);
1831 }
1832
1833 static gboolean
1834 _gst_gl_upload_set_caps_unlocked (GstGLUpload * upload, GstCaps * in_caps,
1835     GstCaps * out_caps)
1836 {
1837   g_return_val_if_fail (upload != NULL, FALSE);
1838   g_return_val_if_fail (gst_caps_is_fixed (in_caps), FALSE);
1839
1840   if (upload->priv->in_caps && upload->priv->out_caps
1841       && gst_caps_is_equal (upload->priv->in_caps, in_caps)
1842       && gst_caps_is_equal (upload->priv->out_caps, out_caps))
1843     return TRUE;
1844
1845   gst_caps_replace (&upload->priv->in_caps, in_caps);
1846   gst_caps_replace (&upload->priv->out_caps, out_caps);
1847
1848   gst_video_info_from_caps (&upload->priv->in_info, in_caps);
1849   gst_video_info_from_caps (&upload->priv->out_info, out_caps);
1850
1851   upload->priv->method_impl = NULL;
1852   upload->priv->method_i = 0;
1853
1854   return TRUE;
1855 }
1856
1857 /**
1858  * gst_gl_upload_set_caps:
1859  * @upload: a #GstGLUpload
1860  * @in_caps: input #GstCaps
1861  * @out_caps: output #GstCaps
1862  *
1863  * Initializes @upload with the information required for upload.
1864  *
1865  * Returns: whether @in_caps and @out_caps could be set on @upload
1866  */
1867 gboolean
1868 gst_gl_upload_set_caps (GstGLUpload * upload, GstCaps * in_caps,
1869     GstCaps * out_caps)
1870 {
1871   gboolean ret;
1872
1873   GST_OBJECT_LOCK (upload);
1874   ret = _gst_gl_upload_set_caps_unlocked (upload, in_caps, out_caps);
1875   GST_OBJECT_UNLOCK (upload);
1876
1877   return ret;
1878 }
1879
1880 /**
1881  * gst_gl_upload_get_caps:
1882  * @upload: a #GstGLUpload
1883  * @in_caps: (transfer full) (allow-none) (out): the input #GstCaps
1884  * @out_caps: (transfer full) (allow-none) (out): the output #GstCaps
1885  */
1886 void
1887 gst_gl_upload_get_caps (GstGLUpload * upload, GstCaps ** in_caps,
1888     GstCaps ** out_caps)
1889 {
1890   GST_OBJECT_LOCK (upload);
1891   if (in_caps)
1892     *in_caps =
1893         upload->priv->in_caps ? gst_caps_ref (upload->priv->in_caps) : NULL;
1894   if (out_caps)
1895     *out_caps =
1896         upload->priv->out_caps ? gst_caps_ref (upload->priv->out_caps) : NULL;
1897   GST_OBJECT_UNLOCK (upload);
1898 }
1899
1900 static gboolean
1901 _upload_find_method (GstGLUpload * upload, gpointer last_impl)
1902 {
1903   gint method_i;
1904
1905   /* start with the last used method after explicitly reconfiguring to
1906    * negotiate caps for this method */
1907   if (upload->priv->method_i == 0) {
1908     upload->priv->method_i = upload->priv->saved_method_i;
1909     upload->priv->saved_method_i = 0;
1910   }
1911
1912   if (upload->priv->method_i >= G_N_ELEMENTS (upload_methods)) {
1913     if (last_impl)
1914       upload->priv->method_i = 0;
1915     else
1916       return FALSE;
1917   }
1918
1919   method_i = upload->priv->method_i;
1920
1921   if (last_impl == upload->priv->upload_impl[method_i])
1922     return FALSE;
1923
1924   upload->priv->method = upload_methods[method_i];
1925   upload->priv->method_impl = upload->priv->upload_impl[method_i];
1926
1927   GST_DEBUG_OBJECT (upload, "attempting upload with uploader %s",
1928       upload->priv->method->name);
1929
1930   upload->priv->method_i++;
1931
1932   return TRUE;
1933 }
1934
1935 /**
1936  * gst_gl_upload_perform_with_buffer:
1937  * @upload: a #GstGLUpload
1938  * @buffer: input #GstBuffer
1939  * @outbuf_ptr: (out): resulting #GstBuffer
1940  *
1941  * Uploads @buffer using the transformation specified by
1942  * gst_gl_upload_set_caps() creating a new #GstBuffer in @outbuf_ptr.
1943  *
1944  * Returns: whether the upload was successful
1945  */
1946 GstGLUploadReturn
1947 gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
1948     GstBuffer ** outbuf_ptr)
1949 {
1950   GstGLUploadReturn ret = GST_GL_UPLOAD_ERROR;
1951   GstBuffer *outbuf;
1952   gpointer last_impl = upload->priv->method_impl;
1953
1954   g_return_val_if_fail (GST_IS_GL_UPLOAD (upload), FALSE);
1955   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
1956   g_return_val_if_fail (outbuf_ptr != NULL, FALSE);
1957
1958   GST_OBJECT_LOCK (upload);
1959
1960 #define NEXT_METHOD \
1961 do { \
1962   if (!_upload_find_method (upload, last_impl)) { \
1963     GST_OBJECT_UNLOCK (upload); \
1964     return FALSE; \
1965   } \
1966   goto restart; \
1967 } while (0)
1968
1969   if (!upload->priv->method_impl)
1970     _upload_find_method (upload, last_impl);
1971
1972 restart:
1973   if (!upload->priv->method->accept (upload->priv->method_impl, buffer,
1974           upload->priv->in_caps, upload->priv->out_caps))
1975     NEXT_METHOD;
1976
1977   ret =
1978       upload->priv->method->perform (upload->priv->method_impl, buffer,
1979       &outbuf);
1980   if (ret == GST_GL_UPLOAD_UNSHARED_GL_CONTEXT) {
1981     gint i;
1982
1983     for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
1984       if (upload_methods[i] == &_raw_data_upload) {
1985         upload->priv->method = &_raw_data_upload;
1986         upload->priv->method_impl = upload->priv->upload_impl[i];
1987         upload->priv->method_i = i;
1988
1989         break;
1990       }
1991     }
1992     goto restart;
1993   } else if (ret == GST_GL_UPLOAD_DONE || ret == GST_GL_UPLOAD_RECONFIGURE) {
1994     if (last_impl != upload->priv->method_impl) {
1995       GstCaps *caps = gst_gl_upload_transform_caps (upload, upload->context,
1996           GST_PAD_SINK, upload->priv->in_caps, NULL);
1997       if (!gst_caps_is_equal (upload->priv->out_caps, caps)) {
1998         gst_buffer_replace (&outbuf, NULL);
1999         ret = GST_GL_UPLOAD_RECONFIGURE;
2000       }
2001       gst_caps_unref (caps);
2002     }
2003     /* we are done */
2004   } else {
2005     upload->priv->method_impl = NULL;
2006     NEXT_METHOD;
2007   }
2008
2009   if (outbuf && buffer != outbuf)
2010     gst_buffer_copy_into (outbuf, buffer,
2011         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2012   *outbuf_ptr = outbuf;
2013
2014   if (ret == GST_GL_UPLOAD_RECONFIGURE)
2015     upload->priv->saved_method_i = upload->priv->method_i - 1;
2016
2017   GST_OBJECT_UNLOCK (upload);
2018
2019   return ret;
2020
2021 #undef NEXT_METHOD
2022 }