• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <string.h>
26 
27 #include "gstglmemory.h"
28 
29 #include "gl.h"
30 #include "gstglcontext_private.h"
31 #include "gstglfuncs.h"
32 
33 /**
34  * SECTION:gstglmemory
35  * @title: GstGLMemory
36  * @short_description: memory subclass for GL textures
37  * @see_also: #GstMemory, #GstAllocator, #GstGLBufferPool
38  *
39  * GstGLMemory is a #GstGLBaseMemory subclass providing support for the mapping of
40  * OpenGL textures.
41  *
42  * #GstGLMemory is created or wrapped through gst_gl_base_memory_alloc()
43  * with #GstGLVideoAllocationParams.
44  *
45  * Data is uploaded or downloaded from the GPU as is necessary.
46  *
47  * The #GstCaps that is used for #GstGLMemory based buffers should contain
48  * the %GST_CAPS_FEATURE_MEMORY_GL_MEMORY as a #GstCapsFeatures and should
49  * contain a 'texture-target' field with one of the #GstGLTextureTarget values
50  * as a string, i.e. some combination of 'texture-target=(string){2D,
51  * rectangle, external-oes}'.
52  */
53 
54 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
55 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
56 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
57 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
58 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
59 
60 #define GL_MEM_WIDTH(gl_mem) _get_plane_width (&gl_mem->info, gl_mem->plane)
61 #define GL_MEM_HEIGHT(gl_mem) _get_plane_height (&gl_mem->info, gl_mem->plane)
62 #define GL_MEM_STRIDE(gl_mem) GST_VIDEO_INFO_PLANE_STRIDE (&gl_mem->info, gl_mem->plane)
63 
64 static GstAllocator *_gl_memory_allocator;
65 
66 GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY);
67 #define GST_CAT_DEFAULT GST_CAT_GL_MEMORY
68 
69 /* compatibility definitions... */
70 #ifndef GL_UNPACK_ROW_LENGTH
71 #define GL_UNPACK_ROW_LENGTH 0x0CF2
72 #endif
73 
74 #ifndef GL_TEXTURE_RECTANGLE
75 #define GL_TEXTURE_RECTANGLE 0x84F5
76 #endif
77 #ifndef GL_TEXTURE_EXTERNAL_OES
78 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
79 #endif
80 
81 #ifndef GL_READ_FRAMEBUFFER
82 #define GL_READ_FRAMEBUFFER 0x8CA8
83 #endif
84 #ifndef GL_DRAW_FRAMEBUFFER
85 #define GL_DRAW_FRAMEBUFFER 0x8CA9
86 #endif
87 
88 G_DEFINE_TYPE (GstGLMemoryAllocator, gst_gl_memory_allocator,
89     GST_TYPE_GL_BASE_MEMORY_ALLOCATOR);
90 
91 GST_DEFINE_MINI_OBJECT_TYPE (GstGLMemory, gst_gl_memory);
92 
93 typedef struct
94 {
95   /* in */
96   GstGLMemory *src;
97   GstGLFormat out_format;
98   guint out_width, out_height;
99   GstGLTextureTarget tex_target;
100   GstGLFormat tex_format;
101   /* inout */
102   guint tex_id;
103   /* out */
104   gboolean result;
105 } GstGLMemoryCopyParams;
106 
107 static inline guint
_get_plane_width(const GstVideoInfo * info,guint plane)108 _get_plane_width (const GstVideoInfo * info, guint plane)
109 {
110   if (GST_VIDEO_INFO_IS_YUV (info)) {
111     gint comp[GST_VIDEO_MAX_COMPONENTS];
112     gst_video_format_info_component (info->finfo, plane, comp);
113     return GST_VIDEO_INFO_COMP_WIDTH (info, comp[0]);
114   } else {
115     /* RGB, GRAY */
116     return GST_VIDEO_INFO_WIDTH (info);
117   }
118 }
119 
120 static inline guint
_get_plane_height(const GstVideoInfo * info,guint plane)121 _get_plane_height (const GstVideoInfo * info, guint plane)
122 {
123   if (GST_VIDEO_INFO_IS_YUV (info)) {
124     gint comp[GST_VIDEO_MAX_COMPONENTS];
125     gst_video_format_info_component (info->finfo, plane, comp);
126     return GST_VIDEO_INFO_COMP_HEIGHT (info, comp[0]);
127   } else {
128     /* RGB, GRAY */
129     return GST_VIDEO_INFO_HEIGHT (info);
130   }
131 }
132 
133 static inline void
_calculate_unpack_length(GstGLMemory * gl_mem,GstGLContext * context)134 _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context)
135 {
136   guint n_gl_bytes;
137   GstGLFormat tex_format;
138   guint tex_type;
139 
140   gl_mem->tex_scaling[0] = 1.0f;
141   gl_mem->tex_scaling[1] = 1.0f;
142   gl_mem->unpack_length = 1;
143   gl_mem->tex_width = GL_MEM_WIDTH (gl_mem);
144 
145   gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &tex_format,
146       &tex_type);
147   n_gl_bytes = gst_gl_format_type_n_bytes (tex_format, tex_type);
148   if (n_gl_bytes == 0) {
149     GST_ERROR ("Unsupported texture type %d", gl_mem->tex_format);
150     return;
151   }
152 
153   if (USING_OPENGL (context) || USING_GLES3 (context)
154       || USING_OPENGL3 (context)) {
155     gl_mem->unpack_length = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
156   } else if (USING_GLES2 (context)) {
157     guint j = 8;
158 
159     while (j >= n_gl_bytes) {
160       /* GST_ROUND_UP_j(GL_MEM_WIDTH (gl_mem) * n_gl_bytes) */
161       guint round_up_j =
162           ((GL_MEM_WIDTH (gl_mem) * n_gl_bytes) + j - 1) & ~(j - 1);
163 
164       if (round_up_j == GL_MEM_STRIDE (gl_mem)) {
165         GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on "
166             "width (with plane width:%u, plane stride:%u and pixel stride:%u. "
167             "RU%u(%u*%u) = %u)", j, GL_MEM_WIDTH (gl_mem),
168             GL_MEM_STRIDE (gl_mem), n_gl_bytes, j, GL_MEM_WIDTH (gl_mem),
169             n_gl_bytes, round_up_j);
170 
171         gl_mem->unpack_length = j;
172         break;
173       }
174       j >>= 1;
175     }
176 
177     if (j < n_gl_bytes) {
178       /* Failed to find a suitable alignment, try based on plane_stride and
179        * scale in the shader.  Useful for alignments that are greater than 8.
180        */
181       j = 8;
182 
183       while (j >= n_gl_bytes) {
184         /* GST_ROUND_UP_j((GL_MEM_STRIDE (gl_mem)) */
185         guint round_up_j = ((GL_MEM_STRIDE (gl_mem)) + j - 1) & ~(j - 1);
186 
187         if (round_up_j == (GL_MEM_STRIDE (gl_mem))) {
188           GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based "
189               "on stride (with plane stride:%u and pixel stride:%u. "
190               "RU%u(%u) = %u)", j, GL_MEM_STRIDE (gl_mem), n_gl_bytes, j,
191               GL_MEM_STRIDE (gl_mem), round_up_j);
192 
193           gl_mem->unpack_length = j;
194           gl_mem->tex_scaling[0] =
195               (gfloat) (GL_MEM_WIDTH (gl_mem) * n_gl_bytes) /
196               (gfloat) GL_MEM_STRIDE (gl_mem);
197           gl_mem->tex_width = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
198           break;
199         }
200         j >>= 1;
201       }
202 
203       if (j < n_gl_bytes) {
204         GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to find matching "
205             "alignment. Image may look corrupted. plane width:%u, "
206             "plane stride:%u and pixel stride:%u", GL_MEM_WIDTH (gl_mem),
207             GL_MEM_STRIDE (gl_mem), n_gl_bytes);
208       }
209     }
210   }
211 
212   if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_RECTANGLE) {
213     guint w_sub =
214         GST_VIDEO_FORMAT_INFO_W_SUB (gl_mem->info.finfo, gl_mem->plane);
215     guint h_sub =
216         GST_VIDEO_FORMAT_INFO_H_SUB (gl_mem->info.finfo, gl_mem->plane);
217 
218     if (w_sub)
219       gl_mem->tex_scaling[0] /= (1 << w_sub);
220     if (h_sub)
221       gl_mem->tex_scaling[1] /= (1 << h_sub);
222   }
223 }
224 
225 static guint
_new_texture(GstGLContext * context,guint target,guint internal_format,guint format,guint type,guint width,guint height)226 _new_texture (GstGLContext * context, guint target, guint internal_format,
227     guint format, guint type, guint width, guint height)
228 {
229   const GstGLFuncs *gl = context->gl_vtable;
230   guint tex_id;
231 
232   gl->GenTextures (1, &tex_id);
233   gl->BindTexture (target, tex_id);
234   if (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE)
235     gl->TexImage2D (target, 0, internal_format, width, height, 0, format, type,
236         NULL);
237 
238   gl->TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
239   gl->TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240   gl->TexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
241   gl->TexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
242 
243   gl->BindTexture (target, 0);
244 
245   return tex_id;
246 }
247 
248 static gboolean
_gl_tex_create(GstGLMemory * gl_mem,GError ** error)249 _gl_tex_create (GstGLMemory * gl_mem, GError ** error)
250 {
251   GstGLContext *context = gl_mem->mem.context;
252   GstGLFormat internal_format;
253   GstGLFormat tex_format;
254   GLenum tex_type;
255 
256   internal_format = gl_mem->tex_format;
257   gst_gl_format_type_from_sized_gl_format (internal_format, &tex_format,
258       &tex_type);
259   internal_format =
260       gst_gl_sized_gl_format_from_gl_format_type (context, tex_format,
261       tex_type);
262 
263   if (!gl_mem->texture_wrapped) {
264     gl_mem->tex_id =
265         _new_texture (context, gst_gl_texture_target_to_gl (gl_mem->tex_target),
266         internal_format, tex_format, tex_type, gl_mem->tex_width,
267         GL_MEM_HEIGHT (gl_mem));
268 
269     GST_TRACE ("Generating texture id:%u format:%u type:%u dimensions:%ux%u",
270         gl_mem->tex_id, tex_format, tex_type, gl_mem->tex_width,
271         GL_MEM_HEIGHT (gl_mem));
272   }
273 
274   return TRUE;
275 }
276 
277 static void
_gst_gl_memory_start_log(GstGLMemory * gl_mem,const gchar * func_name)278 _gst_gl_memory_start_log (GstGLMemory * gl_mem, const gchar * func_name)
279 {
280   /* debugging is disabled */
281   if (!GST_GL_BASE_MEMORY_CAST (gl_mem)->query)
282     return;
283 
284   gst_gl_query_start_log (GST_GL_BASE_MEMORY_CAST (gl_mem)->query,
285       GST_CAT_GL_MEMORY, GST_LEVEL_LOG, NULL, "%s took", func_name);
286 }
287 
288 static void
_gst_gl_memory_end_log(GstGLMemory * gl_mem)289 _gst_gl_memory_end_log (GstGLMemory * gl_mem)
290 {
291   /* debugging is disabled */
292   if (!GST_GL_BASE_MEMORY_CAST (gl_mem)->query)
293     return;
294 
295   gst_gl_query_end (GST_GL_BASE_MEMORY_CAST (gl_mem)->query);
296 }
297 
298 /**
299  * gst_gl_memory_init:
300  * @mem: the #GstGLBaseMemory to initialize
301  * @allocator: the #GstAllocator to initialize with
302  * @parent: (allow-none): the parent #GstMemory to initialize with
303  * @context: the #GstGLContext to initialize with
304  * @target: the #GstGLTextureTarget for this #GstGLMemory
305  * @tex_format: the #GstGLFormat for this #GstGLMemory
306  * @params: (allow-none): the @GstAllocationParams to initialize with
307  * @info: the #GstVideoInfo for this #GstGLMemory
308  * @plane: the plane number (starting from 0) for this #GstGLMemory
309  * @valign: (allow-none): optional #GstVideoAlignment parameters
310  * @notify: (allow-none): a #GDestroyNotify
311  * @user_data: (allow-none): user data to call @notify with
312  *
313  * Initializes @mem with the required parameters.  @info is assumed to have
314  * already have been modified with gst_video_info_align().
315  *
316  * Since: 1.8
317  */
318 void
gst_gl_memory_init(GstGLMemory * mem,GstAllocator * allocator,GstMemory * parent,GstGLContext * context,GstGLTextureTarget target,GstGLFormat tex_format,const GstAllocationParams * params,const GstVideoInfo * info,guint plane,const GstVideoAlignment * valign,gpointer user_data,GDestroyNotify notify)319 gst_gl_memory_init (GstGLMemory * mem, GstAllocator * allocator,
320     GstMemory * parent, GstGLContext * context, GstGLTextureTarget target,
321     GstGLFormat tex_format, const GstAllocationParams * params,
322     const GstVideoInfo * info, guint plane, const GstVideoAlignment * valign,
323     gpointer user_data, GDestroyNotify notify)
324 {
325   const gchar *target_str;
326   gsize size;
327 
328   g_return_if_fail (plane < GST_VIDEO_INFO_N_PLANES (info));
329 
330   mem->info = *info;
331   if (valign)
332     mem->valign = *valign;
333   else
334     gst_video_alignment_reset (&mem->valign);
335 
336   /* double-check alignment requirements (caller should've taken care of this) */
337   if (params) {
338     guint max_align, n;
339 
340     max_align = gst_memory_alignment;
341     max_align |= params->align;
342     for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
343       max_align |= mem->valign.stride_align[n];
344 
345     if (params->align < max_align && max_align > gst_memory_alignment) {
346       GST_WARNING ("allocation params alignment %" G_GSIZE_FORMAT " is smaller "
347           "than the max required video alignment %u", params->align, max_align);
348     }
349   }
350 
351   size = gst_gl_get_plane_data_size (info, valign, plane);
352 
353   mem->tex_target = target;
354   mem->tex_format = tex_format;
355   mem->plane = plane;
356 
357   _calculate_unpack_length (mem, context);
358 
359   gst_gl_base_memory_init ((GstGLBaseMemory *) mem, allocator, parent, context,
360       params, size, user_data, notify);
361 
362   target_str = gst_gl_texture_target_to_string (target);
363   GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture context:%"
364       GST_PTR_FORMAT " memory:%p target:%s format:%u dimensions:%ux%u "
365       "stride:%u size:%" G_GSIZE_FORMAT, context, mem, target_str,
366       mem->tex_format, mem->tex_width, GL_MEM_HEIGHT (mem), GL_MEM_STRIDE (mem),
367       mem->mem.mem.size);
368 }
369 
370 /**
371  * gst_gl_memory_read_pixels:
372  * @gl_mem: a #GstGLMemory
373  * @write_pointer: the data pointer to pass to glReadPixels
374  *
375  * Reads the texture in #GstGLMemory into @write_pointer if no buffer is bound
376  * to `GL_PIXEL_PACK_BUFFER`.  Otherwise @write_pointer is the byte offset into
377  * the currently bound `GL_PIXEL_PACK_BUFFER` buffer to store the result of
378  * glReadPixels.  See the OpenGL specification for glReadPixels for more
379  * details.
380  *
381  * Returns: whether theread operation succeeded
382  *
383  * Since: 1.8
384  */
385 gboolean
gst_gl_memory_read_pixels(GstGLMemory * gl_mem,gpointer write_pointer)386 gst_gl_memory_read_pixels (GstGLMemory * gl_mem, gpointer write_pointer)
387 {
388   GstGLContext *context = gl_mem->mem.context;
389   const GstGLFuncs *gl = context->gl_vtable;
390   GstGLFormat format;
391   guint type;
392   guint fbo;
393 
394   gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &format, &type);
395 
396   /* FIXME: avoid creating a framebuffer every download/copy */
397   gl->GenFramebuffers (1, &fbo);
398   gl->BindFramebuffer (GL_FRAMEBUFFER, fbo);
399 
400   gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
401       gst_gl_texture_target_to_gl (gl_mem->tex_target), gl_mem->tex_id, 0);
402 
403   if (!gst_gl_context_check_framebuffer_status (context, GL_FRAMEBUFFER)) {
404     GST_CAT_WARNING (GST_CAT_GL_MEMORY,
405         "Could not create framebuffer to read pixels for memory %p", gl_mem);
406     gl->DeleteFramebuffers (1, &fbo);
407     return FALSE;
408   }
409 
410   if (USING_GLES2 (context) || USING_GLES3 (context)) {
411     if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
412       /* explicitly supported */
413     } else {
414       gint supported_format, supported_type;
415 
416       gl->GetIntegerv (GL_IMPLEMENTATION_COLOR_READ_FORMAT, &supported_format);
417       gl->GetIntegerv (GL_IMPLEMENTATION_COLOR_READ_TYPE, &supported_type);
418 
419       if (supported_format != format || supported_type != type) {
420         GST_CAT_ERROR (GST_CAT_GL_MEMORY, "cannot read pixels with "
421             "unsupported format and type.  Supported format 0x%x type 0x%x",
422             supported_format, supported_type);
423         gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
424         gl->DeleteFramebuffers (1, &fbo);
425         return FALSE;
426       }
427     }
428   }
429 
430   _gst_gl_memory_start_log (gl_mem, "glReadPixels");
431   gl->ReadPixels (0, 0, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem), format,
432       type, write_pointer);
433   _gst_gl_memory_end_log (gl_mem);
434 
435   gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
436   gl->DeleteFramebuffers (1, &fbo);
437 
438   return TRUE;
439 }
440 
441 static gpointer
_gl_tex_download_get_tex_image(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)442 _gl_tex_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info,
443     gsize size)
444 {
445   GstGLContext *context = gl_mem->mem.context;
446   const GstGLFuncs *gl = context->gl_vtable;
447 
448   if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize)
449     return NULL;
450 
451   if (USING_GLES2 (context) || USING_GLES3 (context))
452     return NULL;
453 
454   /* taken care of by read pixels */
455   if (gl_mem->tex_format != GST_GL_LUMINANCE
456       && gl_mem->tex_format != GST_GL_LUMINANCE_ALPHA)
457     return NULL;
458 
459   if (info->flags & GST_MAP_READ
460       && GST_MEMORY_FLAG_IS_SET (gl_mem,
461           GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
462     GstGLFormat format;
463     guint type;
464     guint target;
465 
466     GST_CAT_TRACE (GST_CAT_GL_MEMORY, "attempting download of texture %u "
467         "using glGetTexImage", gl_mem->tex_id);
468 
469     gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &format,
470         &type);
471 
472     target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
473     gl->BindTexture (target, gl_mem->tex_id);
474     _gst_gl_memory_start_log (gl_mem, "glGetTexImage");
475     gl->GetTexImage (target, 0, format, type, gl_mem->mem.data);
476     _gst_gl_memory_end_log (gl_mem);
477     gl->BindTexture (target, 0);
478   }
479 
480   return gl_mem->mem.data;
481 }
482 
483 static gpointer
_gl_tex_download_read_pixels(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)484 _gl_tex_download_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info,
485     gsize size)
486 {
487   if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize)
488     return NULL;
489 
490   if (info->flags & GST_MAP_READ
491       && GST_MEMORY_FLAG_IS_SET (gl_mem,
492           GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
493     GST_CAT_TRACE (GST_CAT_GL_MEMORY,
494         "attempting download of texture %u " "using glReadPixels",
495         gl_mem->tex_id);
496     if (!gst_gl_memory_read_pixels (gl_mem, gl_mem->mem.data))
497       return NULL;
498   }
499 
500   return gl_mem->mem.data;
501 }
502 
503 static gpointer
_gl_tex_map_cpu_access(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)504 _gl_tex_map_cpu_access (GstGLMemory * gl_mem, GstMapInfo * info, gsize size)
505 {
506   gpointer data = NULL;
507 
508   if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (gl_mem)))
509     return NULL;
510 
511   if (!data)
512     data = _gl_tex_download_get_tex_image (gl_mem, info, size);
513 
514   if (!data)
515     data = _gl_tex_download_read_pixels (gl_mem, info, size);
516 
517   return data;
518 }
519 
520 static void
_upload_cpu_write(GstGLMemory * gl_mem,GstMapInfo * info,gsize maxsize)521 _upload_cpu_write (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize)
522 {
523   gst_gl_memory_texsubimage (gl_mem, gl_mem->mem.data);
524 }
525 
526 /**
527  * gst_gl_memory_texsubimage:
528  * @gl_mem: a #GstGLMemory
529  * @read_pointer: the data pointer to pass to glTexSubImage
530  *
531  * Reads the texture in @read_pointer into @gl_mem.
532  *
533  * See gst_gl_memory_read_pixels() for what @read_pointer signifies.
534  *
535  * Since: 1.8
536  */
537 void
gst_gl_memory_texsubimage(GstGLMemory * gl_mem,gpointer read_pointer)538 gst_gl_memory_texsubimage (GstGLMemory * gl_mem, gpointer read_pointer)
539 {
540   GstGLContext *context = gl_mem->mem.context;
541   const GstGLFuncs *gl;
542   GstGLFormat gl_format;
543   GLenum gl_type, gl_target;
544   gpointer data;
545   gsize plane_start;
546 
547   if (!GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD))
548     return;
549 
550   gl = context->gl_vtable;
551 
552   gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &gl_format,
553       &gl_type);
554 
555   gl_target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
556 
557   if (USING_OPENGL (context) || USING_GLES3 (context)
558       || USING_OPENGL3 (context)) {
559     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length);
560   } else if (USING_GLES2 (context)) {
561     gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length);
562   }
563 
564   GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, %ux%u",
565       gl_mem->tex_id, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem));
566 
567   /* find the start of the plane data including padding */
568   plane_start =
569       gst_gl_get_plane_start (&gl_mem->info, &gl_mem->valign,
570       gl_mem->plane) + gl_mem->mem.mem.offset;
571 
572   data = (gpointer) ((gintptr) plane_start + (gintptr) read_pointer);
573 
574   gl->BindTexture (gl_target, gl_mem->tex_id);
575   _gst_gl_memory_start_log (gl_mem, "glTexSubImage");
576   gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->tex_width,
577       GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, data);
578   _gst_gl_memory_end_log (gl_mem);
579 
580   /* Reset to default values */
581   if (USING_OPENGL (context) || USING_GLES3 (context)
582       || USING_OPENGL3 (context)) {
583     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
584   } else if (USING_GLES2 (context)) {
585     gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
586   }
587 
588   gl->BindTexture (gl_target, 0);
589 }
590 
591 static gpointer
_default_gl_tex_map(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)592 _default_gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize size)
593 {
594   if ((info->flags & GST_MAP_GL) == GST_MAP_GL) {
595     _upload_cpu_write (gl_mem, info, size);
596     return &gl_mem->tex_id;
597   } else {
598     return _gl_tex_map_cpu_access (gl_mem, info, size);
599   }
600 }
601 
602 static gpointer
_gl_tex_map(GstGLMemory * gl_mem,GstMapInfo * info,gsize maxsize)603 _gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize)
604 {
605   GstGLMemoryAllocatorClass *alloc_class;
606   gpointer data;
607 
608   alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator);
609 
610   if ((info->flags & GST_MAP_GL) == GST_MAP_GL) {
611     if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
612       return &gl_mem->tex_id;
613   } else {                      /* not GL */
614     if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
615       GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot map External OES textures");
616       return NULL;
617     }
618   }
619 
620   g_return_val_if_fail (alloc_class->map != NULL, NULL);
621   data = alloc_class->map (GST_GL_BASE_MEMORY_CAST (gl_mem), info, maxsize);
622 
623   return data;
624 }
625 
626 static void
_default_gl_tex_unmap(GstGLMemory * gl_mem,GstMapInfo * info)627 _default_gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info)
628 {
629 }
630 
631 static void
_gl_tex_unmap(GstGLMemory * gl_mem,GstMapInfo * info)632 _gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info)
633 {
634   GstGLMemoryAllocatorClass *alloc_class;
635 
636   alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator);
637   g_return_if_fail (alloc_class->unmap != NULL);
638 
639   alloc_class->unmap (GST_GL_BASE_MEMORY_CAST (gl_mem), info);
640 }
641 
642 /**
643  * gst_gl_memory_copy_teximage:
644  * @src: the source #GstGLMemory
645  * @tex_id: the destination texture id
646  * @out_target: the destination #GstGLTextureTarget
647  * @out_tex_format: the destination #GstGLFormat
648  * @out_width: the destination width
649  * @out_height: the destination height
650  *
651  * Copies the texture in #GstGLMemory into the texture specified by @tex_id,
652  * @out_target, @out_tex_format, @out_width and @out_height.
653  *
654  * Returns: whether the copy succeeded.
655  *
656  * Since: 1.8
657  */
658 gboolean
gst_gl_memory_copy_teximage(GstGLMemory * src,guint tex_id,GstGLTextureTarget out_target,GstGLFormat out_tex_format,gint out_width,gint out_height)659 gst_gl_memory_copy_teximage (GstGLMemory * src, guint tex_id,
660     GstGLTextureTarget out_target, GstGLFormat out_tex_format,
661     gint out_width, gint out_height)
662 {
663   const GstGLFuncs *gl;
664   guint out_tex_target;
665   GstMapInfo sinfo;
666   guint src_tex_id;
667   guint fbo[2];
668   guint n_fbos;
669 
670   gl = src->mem.context->gl_vtable;
671   out_tex_target = gst_gl_texture_target_to_gl (out_target);
672 
673   if (!gl->GenFramebuffers) {
674     GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Framebuffer objects not supported");
675     goto error;
676   }
677 
678   if (USING_GLES2 (src->mem.context)
679       && (src->tex_format == GST_GL_LUMINANCE
680           || src->tex_format == GST_GL_LUMINANCE_ALPHA)) {
681     GST_CAT_FIXME (GST_CAT_GL_MEMORY,
682         "Cannot copy Luminance/Luminance Alpha textures in GLES");
683     goto error;
684   }
685 
686   if (!gst_memory_map (GST_MEMORY_CAST (src), &sinfo,
687           GST_MAP_READ | GST_MAP_GL)) {
688     GST_CAT_ERROR (GST_CAT_GL_MEMORY,
689         "Failed to map source memory for copying");
690     goto error;
691   }
692 
693   src_tex_id = *(guint *) sinfo.data;
694 
695   GST_CAT_LOG (GST_CAT_GL_MEMORY, "copying memory %p, tex %u into "
696       "texture %i", src, src_tex_id, tex_id);
697 
698   /* FIXME: try and avoid creating and destroying fbo's every copy... */
699   if (!gl->BlitFramebuffer || (!gl->DrawBuffer && !gl->DrawBuffers)
700       || !gl->ReadBuffer) {
701     /* create a framebuffer object */
702     n_fbos = 1;
703     gl->GenFramebuffers (n_fbos, &fbo[0]);
704     gl->BindFramebuffer (GL_FRAMEBUFFER, fbo[0]);
705 
706     gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
707         gst_gl_texture_target_to_gl (src->tex_target), src_tex_id, 0);
708 
709     if (!gst_gl_context_check_framebuffer_status (src->mem.context,
710             GL_FRAMEBUFFER))
711       goto fbo_error;
712 
713     gl->BindTexture (out_tex_target, tex_id);
714     _gst_gl_memory_start_log (src, "CopyTexImage2D");
715     gl->CopyTexImage2D (out_tex_target, 0, out_tex_format, 0, 0, out_width,
716         out_height, 0);
717     _gst_gl_memory_end_log (src);
718 
719     gl->BindTexture (out_tex_target, 0);
720     gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
721 
722     gl->DeleteFramebuffers (n_fbos, &fbo[0]);
723   } else {
724     GLenum multipleRT[] = {
725       GL_COLOR_ATTACHMENT0,
726       GL_COLOR_ATTACHMENT1,
727       GL_COLOR_ATTACHMENT2
728     };
729 
730     /* create a framebuffer object */
731     n_fbos = 2;
732     gl->GenFramebuffers (n_fbos, &fbo[0]);
733 
734     gl->BindFramebuffer (GL_READ_FRAMEBUFFER, fbo[0]);
735     gl->FramebufferTexture2D (GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
736         gst_gl_texture_target_to_gl (src->tex_target), src_tex_id, 0);
737 
738     if (!gst_gl_context_check_framebuffer_status (src->mem.context,
739             GL_READ_FRAMEBUFFER))
740       goto fbo_error;
741 
742     gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, fbo[1]);
743 
744     gl->FramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
745         gst_gl_texture_target_to_gl (src->tex_target), tex_id, 0);
746 
747     if (!gst_gl_context_check_framebuffer_status (src->mem.context,
748             GL_DRAW_FRAMEBUFFER))
749       goto fbo_error;
750 
751     gl->BindTexture (out_tex_target, tex_id);
752     _gst_gl_memory_start_log (src, "BlitFramebuffer");
753     gl->ReadBuffer (GL_COLOR_ATTACHMENT0);
754     if (gl->DrawBuffers)
755       gl->DrawBuffers (1, multipleRT);
756     else
757       gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
758     gl->BlitFramebuffer (0, 0, out_width, out_height,
759         0, 0, out_width, out_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
760     _gst_gl_memory_end_log (src);
761 
762     gl->BindTexture (out_tex_target, 0);
763     gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
764     gl->BindFramebuffer (GL_READ_FRAMEBUFFER, 0);
765 
766     gl->DeleteFramebuffers (n_fbos, &fbo[0]);
767 
768     if (gl->DrawBuffer)
769       gl->DrawBuffer (GL_BACK);
770   }
771 
772   gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo);
773 
774   return TRUE;
775 
776 fbo_error:
777   {
778     gl->BindTexture (out_tex_target, 0);
779     if (!gl->BlitFramebuffer) {
780       gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
781     } else {
782       gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
783       gl->BindFramebuffer (GL_READ_FRAMEBUFFER, 0);
784     }
785 
786     gl->DeleteFramebuffers (n_fbos, &fbo[0]);
787 
788     gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo);
789   }
790 error:
791   return FALSE;
792 }
793 
794 static void
_gl_tex_copy_thread(GstGLContext * context,gpointer data)795 _gl_tex_copy_thread (GstGLContext * context, gpointer data)
796 {
797   GstGLMemoryCopyParams *copy_params;
798 
799   copy_params = (GstGLMemoryCopyParams *) data;
800 
801   if (!copy_params->tex_id) {
802     GstGLFormat internal_format, out_gl_format;
803     guint out_gl_type, out_tex_target;
804 
805     out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target);
806     internal_format = copy_params->src->tex_format;
807     gst_gl_format_type_from_sized_gl_format (internal_format, &out_gl_format,
808         &out_gl_type);
809     internal_format =
810         gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format,
811         out_gl_type);
812 
813     copy_params->tex_id =
814         _new_texture (context, out_tex_target,
815         internal_format, out_gl_format, out_gl_type, copy_params->out_width,
816         copy_params->out_height);
817   }
818 
819   copy_params->result = gst_gl_memory_copy_teximage (copy_params->src,
820       copy_params->tex_id, copy_params->tex_target, copy_params->tex_format,
821       copy_params->out_width, copy_params->out_height);
822 }
823 
824 static GstMemory *
_default_gl_tex_copy(GstGLMemory * src,gssize offset,gssize size)825 _default_gl_tex_copy (GstGLMemory * src, gssize offset, gssize size)
826 {
827   GstAllocationParams params = { 0, GST_MEMORY_CAST (src)->align, 0, 0 };
828   GstGLBaseMemoryAllocator *base_mem_allocator;
829   GstAllocator *allocator;
830   GstGLMemory *dest = NULL;
831 
832   allocator = GST_MEMORY_CAST (src)->allocator;
833   base_mem_allocator = (GstGLBaseMemoryAllocator *) allocator;
834 
835   if (src->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
836     GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures");
837     return NULL;
838   }
839 
840   /* If not doing a full copy, then copy to sysmem, the 2D represention of the
841    * texture would become wrong */
842   if (offset > 0 || size < GST_MEMORY_CAST (src)->size) {
843     return base_mem_allocator->fallback_mem_copy (GST_MEMORY_CAST (src), offset,
844         size);
845   }
846 
847   dest = g_new0 (GstGLMemory, 1);
848 
849   gst_gl_memory_init (dest, allocator, NULL, src->mem.context, src->tex_target,
850       src->tex_format, &params, &src->info, src->plane, &src->valign, NULL,
851       NULL);
852 
853   if (!GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) {
854     GstMapInfo dinfo;
855 
856     if (!gst_memory_map (GST_MEMORY_CAST (dest), &dinfo,
857             GST_MAP_WRITE | GST_MAP_GL)) {
858       GST_CAT_WARNING (GST_CAT_GL_MEMORY,
859           "Failed not map destination for writing");
860       gst_memory_unref (GST_MEMORY_CAST (dest));
861       return NULL;
862     }
863 
864     if (!gst_gl_memory_copy_into ((GstGLMemory *) src,
865             ((GstGLMemory *) dest)->tex_id, src->tex_target,
866             src->tex_format, src->tex_width, GL_MEM_HEIGHT (src))) {
867       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
868       gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo);
869       goto memcpy;
870     }
871 
872     gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo);
873   } else {
874   memcpy:
875     if (!gst_gl_base_memory_memcpy ((GstGLBaseMemory *) src,
876             (GstGLBaseMemory *) dest, offset, size)) {
877       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
878       gst_memory_unref (GST_MEMORY_CAST (dest));
879       return NULL;
880     }
881   }
882 
883   return (GstMemory *) dest;
884 }
885 
886 static GstMemory *
_gl_tex_copy(GstGLMemory * src,gssize offset,gssize size)887 _gl_tex_copy (GstGLMemory * src, gssize offset, gssize size)
888 {
889   GstGLMemoryAllocatorClass *alloc_class;
890 
891   alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (src->mem.mem.allocator);
892 
893   if (src->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
894     GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures");
895     return NULL;
896   }
897 
898   g_return_val_if_fail (alloc_class->copy, NULL);
899   return (GstMemory *) alloc_class->copy (GST_GL_BASE_MEMORY_CAST (src), offset,
900       size);
901 }
902 
903 static GstMemory *
_gl_tex_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)904 _gl_tex_alloc (GstAllocator * allocator, gsize size,
905     GstAllocationParams * params)
906 {
907   g_warning ("Use gst_gl_base_memory_alloc to allocate from this allocator");
908 
909   return NULL;
910 }
911 
912 static void
_gl_tex_destroy(GstGLMemory * gl_mem)913 _gl_tex_destroy (GstGLMemory * gl_mem)
914 {
915   const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable;
916 
917   if (gl_mem->tex_id && !gl_mem->texture_wrapped)
918     gl->DeleteTextures (1, &gl_mem->tex_id);
919 }
920 
921 static GstGLMemory *
_default_gl_tex_alloc(GstGLMemoryAllocator * allocator,GstGLVideoAllocationParams * params)922 _default_gl_tex_alloc (GstGLMemoryAllocator * allocator,
923     GstGLVideoAllocationParams * params)
924 {
925   guint alloc_flags = params->parent.alloc_flags;
926   GstGLMemory *mem;
927 
928   g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
929       NULL);
930 
931   mem = g_new0 (GstGLMemory, 1);
932 
933   if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
934     mem->tex_id = GPOINTER_TO_UINT (params->parent.gl_handle);
935     mem->texture_wrapped = TRUE;
936   }
937 
938   gst_gl_memory_init (mem, GST_ALLOCATOR_CAST (allocator), NULL,
939       params->parent.context, params->target, params->tex_format,
940       params->parent.alloc_params, params->v_info, params->plane,
941       params->valign, params->parent.user_data, params->parent.notify);
942 
943   if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
944     GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
945   }
946   if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) {
947     mem->mem.data = params->parent.wrapped_data;
948     GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
949   }
950 
951   return mem;
952 }
953 
954 static void
gst_gl_memory_allocator_class_init(GstGLMemoryAllocatorClass * klass)955 gst_gl_memory_allocator_class_init (GstGLMemoryAllocatorClass * klass)
956 {
957   GstGLBaseMemoryAllocatorClass *gl_base;
958   GstAllocatorClass *allocator_class;
959 
960   gl_base = (GstGLBaseMemoryAllocatorClass *) klass;
961   allocator_class = (GstAllocatorClass *) klass;
962 
963   klass->map = (GstGLBaseMemoryAllocatorMapFunction) _default_gl_tex_map;
964   klass->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _default_gl_tex_unmap;
965   klass->copy = (GstGLBaseMemoryAllocatorCopyFunction) _default_gl_tex_copy;
966 
967   gl_base->alloc =
968       (GstGLBaseMemoryAllocatorAllocFunction) _default_gl_tex_alloc;
969   gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_tex_create;
970   gl_base->map = (GstGLBaseMemoryAllocatorMapFunction) _gl_tex_map;
971   gl_base->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _gl_tex_unmap;
972   gl_base->copy = (GstGLBaseMemoryAllocatorCopyFunction) _gl_tex_copy;
973   gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_tex_destroy;
974 
975   allocator_class->alloc = _gl_tex_alloc;
976 }
977 
978 static void
gst_gl_memory_allocator_init(GstGLMemoryAllocator * allocator)979 gst_gl_memory_allocator_init (GstGLMemoryAllocator * allocator)
980 {
981   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
982 
983   alloc->mem_type = GST_GL_MEMORY_ALLOCATOR_NAME;
984 
985   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
986 }
987 
988 /**
989  * gst_gl_memory_copy_into:
990  * @gl_mem:a #GstGLMemory
991  * @tex_id:OpenGL texture id
992  * @target: the #GstGLTextureTarget
993  * @tex_format: the #GstGLFormat
994  * @width: width of @tex_id
995  * @height: height of @tex_id
996  *
997  * Copies @gl_mem into the texture specified by @tex_id.  The format of @tex_id
998  * is specified by @tex_format, @width and @height.
999  *
1000  * Returns: Whether the copy succeeded
1001  *
1002  * Since: 1.8
1003  */
1004 gboolean
gst_gl_memory_copy_into(GstGLMemory * gl_mem,guint tex_id,GstGLTextureTarget target,GstGLFormat tex_format,gint width,gint height)1005 gst_gl_memory_copy_into (GstGLMemory * gl_mem, guint tex_id,
1006     GstGLTextureTarget target, GstGLFormat tex_format, gint width, gint height)
1007 {
1008   GstGLMemoryCopyParams copy_params;
1009 
1010   copy_params.src = gl_mem;
1011   copy_params.tex_id = tex_id;
1012   copy_params.tex_target = target;
1013   copy_params.tex_format = tex_format;
1014   copy_params.out_width = width;
1015   copy_params.out_height = height;
1016 
1017   gst_gl_context_thread_add (gl_mem->mem.context, _gl_tex_copy_thread,
1018       &copy_params);
1019 
1020   return copy_params.result;
1021 }
1022 
1023 /**
1024  * gst_gl_memory_get_texture_width:
1025  * @gl_mem: a #GstGLMemory
1026  *
1027  * Returns: the texture width of @gl_mem
1028  *
1029  * Since: 1.8
1030  */
1031 gint
gst_gl_memory_get_texture_width(GstGLMemory * gl_mem)1032 gst_gl_memory_get_texture_width (GstGLMemory * gl_mem)
1033 {
1034   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1035 
1036   return gl_mem->tex_width;
1037 }
1038 
1039 /**
1040  * gst_gl_memory_get_texture_height:
1041  * @gl_mem: a #GstGLMemory
1042  *
1043  * Returns: the texture height of @gl_mem
1044  *
1045  * Since: 1.8
1046  */
1047 gint
gst_gl_memory_get_texture_height(GstGLMemory * gl_mem)1048 gst_gl_memory_get_texture_height (GstGLMemory * gl_mem)
1049 {
1050   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1051 
1052   return _get_plane_height (&gl_mem->info, gl_mem->plane);
1053 }
1054 
1055 /**
1056  * gst_gl_memory_get_texture_format:
1057  * @gl_mem: a #GstGLMemory
1058  *
1059  * Returns: the #GstGLFormat of @gl_mem
1060  *
1061  * Since: 1.12
1062  */
1063 GstGLFormat
gst_gl_memory_get_texture_format(GstGLMemory * gl_mem)1064 gst_gl_memory_get_texture_format (GstGLMemory * gl_mem)
1065 {
1066   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1067 
1068   return gl_mem->tex_format;
1069 }
1070 
1071 /**
1072  * gst_gl_memory_get_texture_target:
1073  * @gl_mem: a #GstGLMemory
1074  *
1075  * Returns: the #GstGLTextureTarget of @gl_mem
1076  *
1077  * Since: 1.8
1078  */
1079 GstGLTextureTarget
gst_gl_memory_get_texture_target(GstGLMemory * gl_mem)1080 gst_gl_memory_get_texture_target (GstGLMemory * gl_mem)
1081 {
1082   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1083 
1084   return gl_mem->tex_target;
1085 }
1086 
1087 /**
1088  * gst_gl_memory_get_texture_id:
1089  * @gl_mem: a #GstGLMemory
1090  *
1091  * Returns: the OpenGL texture handle of @gl_mem
1092  *
1093  * Since: 1.8
1094  */
1095 guint
gst_gl_memory_get_texture_id(GstGLMemory * gl_mem)1096 gst_gl_memory_get_texture_id (GstGLMemory * gl_mem)
1097 {
1098   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1099 
1100   return gl_mem->tex_id;
1101 }
1102 
1103 /**
1104  * gst_gl_memory_init_once:
1105  *
1106  * Initializes the GL Base Texture allocator. It is safe to call this function
1107  * multiple times.  This must be called before any other GstGLMemory operation.
1108  *
1109  * Since: 1.4
1110  */
1111 void
gst_gl_memory_init_once(void)1112 gst_gl_memory_init_once (void)
1113 {
1114   static gsize _init = 0;
1115 
1116   if (g_once_init_enter (&_init)) {
1117     gst_gl_base_memory_init_once ();
1118 
1119     GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glbasetexture", 0,
1120         "OpenGL Base Texture Memory");
1121 
1122     _gl_memory_allocator = g_object_new (GST_TYPE_GL_MEMORY_ALLOCATOR, NULL);
1123     gst_object_ref_sink (_gl_memory_allocator);
1124 
1125     gst_allocator_register (GST_GL_MEMORY_ALLOCATOR_NAME, _gl_memory_allocator);
1126 
1127     g_once_init_leave (&_init, 1);
1128   }
1129 }
1130 
1131 /**
1132  * gst_is_gl_memory:
1133  * @mem:a #GstMemory
1134  *
1135  * Returns: whether the memory at @mem is a #GstGLMemory
1136  *
1137  * Since: 1.4
1138  */
1139 gboolean
gst_is_gl_memory(GstMemory * mem)1140 gst_is_gl_memory (GstMemory * mem)
1141 {
1142   return mem != NULL && mem->allocator != NULL
1143       && g_type_is_a (G_OBJECT_TYPE (mem->allocator),
1144       GST_TYPE_GL_MEMORY_ALLOCATOR);
1145 }
1146 
1147 G_DEFINE_BOXED_TYPE (GstGLVideoAllocationParams, gst_gl_video_allocation_params,
1148     (GBoxedCopyFunc) gst_gl_allocation_params_copy,
1149     (GBoxedFreeFunc) gst_gl_allocation_params_free);
1150 
1151 static void
_gst_gl_video_allocation_params_set_video_alignment(GstGLVideoAllocationParams * params,const GstVideoAlignment * valign)1152 _gst_gl_video_allocation_params_set_video_alignment (GstGLVideoAllocationParams
1153     * params, const GstVideoAlignment * valign)
1154 {
1155   g_return_if_fail (params != NULL);
1156 
1157   if (!params->valign)
1158     params->valign = g_new0 (GstVideoAlignment, 1);
1159 
1160   if (valign) {
1161     *params->valign = *valign;
1162   } else {
1163     gst_video_alignment_reset (params->valign);
1164   }
1165 }
1166 
1167 /**
1168  * gst_gl_video_allocation_params_init_full: (skip)
1169  * @params: a #GstGLVideoAllocationParams to initialize
1170  * @struct_size: the size of the struct in @params
1171  * @alloc_flags: some allocation flags
1172  * @copy: a copy function
1173  * @free: a free function
1174  * @context: a #GstGLContext
1175  * @alloc_params: (allow-none): the #GstAllocationParams for @wrapped_data
1176  * @v_info: the #GstVideoInfo for @wrapped_data
1177  * @plane: the video plane @wrapped_data represents
1178  * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @wrapped_data
1179  * @target: the #GstGLTextureTarget
1180  * @tex_format: the #GstGLFormat
1181  * @wrapped_data: (allow-none): the optional data pointer to wrap
1182  * @gl_handle: the optional OpenGL handle to wrap or 0
1183  * @user_data: (allow-none): user data to call @notify with
1184  * @notify: (allow-none): a #GDestroyNotify
1185  *
1186  * Intended for subclass usage
1187  *
1188  * Returns: initializes @params with the parameters specified
1189  *
1190  * Since: 1.8
1191  */
1192 gboolean
gst_gl_video_allocation_params_init_full(GstGLVideoAllocationParams * params,gsize struct_size,guint alloc_flags,GstGLAllocationParamsCopyFunc copy,GstGLAllocationParamsFreeFunc free,GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer wrapped_data,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)1193 gst_gl_video_allocation_params_init_full (GstGLVideoAllocationParams * params,
1194     gsize struct_size, guint alloc_flags, GstGLAllocationParamsCopyFunc copy,
1195     GstGLAllocationParamsFreeFunc free, GstGLContext * context,
1196     const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1197     guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1198     GstGLFormat tex_format, gpointer wrapped_data, gpointer gl_handle,
1199     gpointer user_data, GDestroyNotify notify)
1200 {
1201   guint i;
1202 
1203   g_return_val_if_fail (params != NULL, FALSE);
1204   g_return_val_if_fail (copy != NULL, FALSE);
1205   g_return_val_if_fail (free != NULL, FALSE);
1206   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1207   g_return_val_if_fail (v_info != NULL, FALSE);
1208 
1209   memset (params, 0, sizeof (*params));
1210 
1211   if (!gst_gl_allocation_params_init ((GstGLAllocationParams *) params,
1212           struct_size, alloc_flags, copy, free, context, 0, alloc_params,
1213           wrapped_data, gl_handle, user_data, notify))
1214     return FALSE;
1215 
1216   params->v_info = g_new0 (GstVideoInfo, 1);
1217   *params->v_info = *v_info;
1218   for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1219     params->v_info->offset[i] = v_info->offset[i];
1220     params->v_info->stride[i] = v_info->stride[i];
1221   }
1222   _gst_gl_video_allocation_params_set_video_alignment (params, valign);
1223   params->target = target;
1224   params->tex_format = tex_format;
1225   params->plane = plane;
1226 
1227   return TRUE;
1228 }
1229 
1230 /**
1231  * gst_gl_video_allocation_params_new:
1232  * @context: a #GstGLContext
1233  * @alloc_params: (allow-none): the #GstAllocationParams for sysmem mappings of the texture
1234  * @v_info: the #GstVideoInfo for the texture
1235  * @plane: the video plane of @v_info to allocate
1236  * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of the texture
1237  * @target: the #GstGLTextureTarget for the created textures
1238  * @tex_format: the #GstGLFormat for the created textures
1239  *
1240  * Returns: a new #GstGLVideoAllocationParams for allocating #GstGLMemory's
1241  *
1242  * Since: 1.8
1243  */
1244 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format)1245 gst_gl_video_allocation_params_new (GstGLContext * context,
1246     const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1247     guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1248     GstGLFormat tex_format)
1249 {
1250   GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1251 
1252   if (!gst_gl_video_allocation_params_init_full (params,
1253           sizeof (GstGLVideoAllocationParams),
1254           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_ALLOC |
1255           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1256           (GstGLAllocationParamsCopyFunc)
1257           gst_gl_video_allocation_params_copy_data,
1258           (GstGLAllocationParamsFreeFunc)
1259           gst_gl_video_allocation_params_free_data, context, alloc_params,
1260           v_info, plane, valign, target, tex_format, NULL, 0, NULL, NULL)) {
1261     g_free (params);
1262     return NULL;
1263   }
1264 
1265   return params;
1266 }
1267 
1268 /**
1269  * gst_gl_video_allocation_params_new_wrapped_data:
1270  * @context: a #GstGLContext
1271  * @alloc_params: (allow-none): the #GstAllocationParams for @wrapped_data
1272  * @v_info: the #GstVideoInfo for @wrapped_data
1273  * @plane: the video plane @wrapped_data represents
1274  * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @wrapped_data
1275  * @target: the #GstGLTextureTarget for @wrapped_data
1276  * @tex_format: the #GstGLFormat for @wrapped_data
1277  * @wrapped_data: the data pointer to wrap
1278  * @user_data: (allow-none): user data to call @notify with
1279  * @notify: (allow-none): a #GDestroyNotify
1280  *
1281  * Returns: a new #GstGLVideoAllocationParams for wrapping @wrapped_data
1282  *
1283  * Since: 1.8
1284  */
1285 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_data(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer wrapped_data,gpointer user_data,GDestroyNotify notify)1286 gst_gl_video_allocation_params_new_wrapped_data (GstGLContext * context,
1287     const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1288     guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1289     GstGLFormat tex_format, gpointer wrapped_data, gpointer user_data,
1290     GDestroyNotify notify)
1291 {
1292   GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1293 
1294   if (!gst_gl_video_allocation_params_init_full (params,
1295           sizeof (GstGLVideoAllocationParams),
1296           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM |
1297           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1298           (GstGLAllocationParamsCopyFunc)
1299           gst_gl_video_allocation_params_copy_data,
1300           (GstGLAllocationParamsFreeFunc)
1301           gst_gl_video_allocation_params_free_data, context, alloc_params,
1302           v_info, plane, valign, target, tex_format, wrapped_data, 0, user_data,
1303           notify)) {
1304     g_free (params);
1305     return NULL;
1306   }
1307 
1308   return params;
1309 }
1310 
1311 /**
1312  * gst_gl_video_allocation_params_new_wrapped_gl_handle:
1313  * @context: a #GstGLContext
1314  * @alloc_params: (allow-none): the #GstAllocationParams for @tex_id
1315  * @v_info: the #GstVideoInfo for @tex_id
1316  * @plane: the video plane @tex_id represents
1317  * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @tex_id
1318  * @target: the #GstGLTextureTarget for @tex_id
1319  * @tex_format: the #GstGLFormat for @tex_id
1320  * @gl_handle: the GL handle to wrap
1321  * @user_data: (allow-none): user data to call @notify with
1322  * @notify: (allow-none): a #GDestroyNotify
1323  *
1324  * @gl_handle is defined by the specific OpenGL handle being wrapped
1325  * For #GstGLMemory and #GstGLMemoryPBO it is an OpenGL texture id.
1326  * Other memory types may define it to require a different type of parameter.
1327  *
1328  * Returns: a new #GstGLVideoAllocationParams for wrapping @gl_handle
1329  *
1330  * Since: 1.8
1331  */
1332 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_gl_handle(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)1333 gst_gl_video_allocation_params_new_wrapped_gl_handle (GstGLContext * context,
1334     const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1335     guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1336     GstGLFormat tex_format, gpointer gl_handle, gpointer user_data,
1337     GDestroyNotify notify)
1338 {
1339   GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1340 
1341   if (!gst_gl_video_allocation_params_init_full (params,
1342           sizeof (GstGLVideoAllocationParams),
1343           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE |
1344           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1345           (GstGLAllocationParamsCopyFunc)
1346           gst_gl_video_allocation_params_copy_data,
1347           (GstGLAllocationParamsFreeFunc)
1348           gst_gl_video_allocation_params_free_data, context, alloc_params,
1349           v_info, plane, valign, target, tex_format, NULL, gl_handle, user_data,
1350           notify)) {
1351     g_free (params);
1352     return NULL;
1353   }
1354 
1355   return params;
1356 }
1357 
1358 /**
1359  * gst_gl_video_allocation_params_new_wrapped_texture:
1360  * @context: a #GstGLContext
1361  * @alloc_params: (allow-none): the #GstAllocationParams for @tex_id
1362  * @v_info: the #GstVideoInfo for @tex_id
1363  * @plane: the video plane @tex_id represents
1364  * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @tex_id
1365  * @target: the #GstGLTextureTarget for @tex_id
1366  * @tex_format: the #GstGLFormat for @tex_id
1367  * @tex_id: the GL texture to wrap
1368  * @user_data: (allow-none): user data to call @notify with
1369  * @notify: (allow-none): a #GDestroyNotify
1370  *
1371  * Returns: a new #GstGLVideoAllocationParams for wrapping @tex_id
1372  *
1373  * Since: 1.8
1374  */
1375 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_texture(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,guint tex_id,gpointer user_data,GDestroyNotify notify)1376 gst_gl_video_allocation_params_new_wrapped_texture (GstGLContext * context,
1377     const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1378     guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1379     GstGLFormat tex_format, guint tex_id, gpointer user_data,
1380     GDestroyNotify notify)
1381 {
1382   return gst_gl_video_allocation_params_new_wrapped_gl_handle (context,
1383       alloc_params, v_info, plane, valign, target, tex_format,
1384       GUINT_TO_POINTER (tex_id), user_data, notify);
1385 }
1386 
1387 /**
1388  * gst_gl_video_allocation_params_free_data:
1389  * @params: a #GstGLVideoAllocationParams
1390  *
1391  * Unset and free any dynamically allocated resources.  Intended for subclass
1392  * usage only to chain up at the end of a subclass free function.
1393  *
1394  * Since: 1.8
1395  */
1396 void
gst_gl_video_allocation_params_free_data(GstGLVideoAllocationParams * params)1397 gst_gl_video_allocation_params_free_data (GstGLVideoAllocationParams * params)
1398 {
1399   g_free (params->v_info);
1400   g_free (params->valign);
1401 
1402   gst_gl_allocation_params_free_data (&params->parent);
1403 }
1404 
1405 /**
1406  * gst_gl_video_allocation_params_copy_data:
1407  * @src_vid: source #GstGLVideoAllocationParams to copy from
1408  * @dest_vid: destination #GstGLVideoAllocationParams to copy into
1409  *
1410  * Copy and set any dynamically allocated resources in @dest_vid.  Intended
1411  * for subclass usage only to chain up at the end of a subclass copy function.
1412  *
1413  * Since: 1.8
1414  */
1415 void
gst_gl_video_allocation_params_copy_data(GstGLVideoAllocationParams * src_vid,GstGLVideoAllocationParams * dest_vid)1416 gst_gl_video_allocation_params_copy_data (GstGLVideoAllocationParams * src_vid,
1417     GstGLVideoAllocationParams * dest_vid)
1418 {
1419   GstGLAllocationParams *src = (GstGLAllocationParams *) src_vid;
1420   GstGLAllocationParams *dest = (GstGLAllocationParams *) dest_vid;
1421   guint i;
1422 
1423   gst_gl_allocation_params_copy_data (src, dest);
1424 
1425   dest_vid->v_info = g_new0 (GstVideoInfo, 1);
1426   *dest_vid->v_info = *src_vid->v_info;
1427   for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1428     dest_vid->v_info->offset[i] = src_vid->v_info->offset[i];
1429     dest_vid->v_info->stride[i] = src_vid->v_info->stride[i];
1430   }
1431   _gst_gl_video_allocation_params_set_video_alignment (dest_vid,
1432       src_vid->valign);
1433   dest_vid->target = src_vid->target;
1434   dest_vid->tex_format = src_vid->tex_format;
1435   dest_vid->plane = src_vid->plane;
1436 }
1437 
1438 /**
1439  * gst_gl_memory_setup_buffer: (skip)
1440  * @allocator: the @GstGLMemoryAllocator to allocate from
1441  * @buffer: a #GstBuffer to setup
1442  * @params: the #GstGLVideoAllocationParams to allocate with
1443  * @tex_formats: (allow-none) (array length=n_wrapped_pointers):
1444  *     a list of #GstGLFormat's to allocate with.
1445  * @wrapped_data: (array length=n_wrapped_pointers) (element-type gpointer):
1446  *     a list of wrapped data pointers
1447  * @n_wrapped_pointers: the number of elements in @tex_formats and @wrapped_data
1448  *
1449  * Returns: whether the buffer was correctly setup
1450  *
1451  * Since: 1.8
1452  */
1453 gboolean
gst_gl_memory_setup_buffer(GstGLMemoryAllocator * allocator,GstBuffer * buffer,GstGLVideoAllocationParams * params,GstGLFormat * tex_formats,gpointer * wrapped_data,gsize n_wrapped_pointers)1454 gst_gl_memory_setup_buffer (GstGLMemoryAllocator * allocator,
1455     GstBuffer * buffer, GstGLVideoAllocationParams * params,
1456     GstGLFormat * tex_formats, gpointer * wrapped_data,
1457     gsize n_wrapped_pointers)
1458 {
1459   GstGLBaseMemoryAllocator *base_allocator;
1460   guint n_mem, i, v, views;
1461   guint alloc_flags = params->parent.alloc_flags;
1462 
1463   g_return_val_if_fail (params != NULL, FALSE);
1464   g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1465       FALSE);
1466 
1467   base_allocator = GST_GL_BASE_MEMORY_ALLOCATOR (allocator);
1468   n_mem = GST_VIDEO_INFO_N_PLANES (params->v_info);
1469 
1470   if (GST_VIDEO_INFO_MULTIVIEW_MODE (params->v_info) ==
1471       GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
1472     views = params->v_info->views;
1473   else
1474     views = 1;
1475 
1476   if (n_wrapped_pointers == views)
1477     n_mem = 1;
1478 
1479   /* Sanity check for the code below; there should be as many pointers as the
1480    * number of memory we are going to create */
1481   g_return_val_if_fail (!wrapped_data
1482       || n_mem * views == n_wrapped_pointers, FALSE);
1483 
1484   for (v = 0; v < views; v++) {
1485     GstVideoMeta *meta;
1486 
1487     for (i = 0; i < n_mem; i++) {
1488       GstGLMemory *gl_mem;
1489 
1490       if (tex_formats) {
1491         params->tex_format = tex_formats[i];
1492       } else {
1493         params->tex_format =
1494             gst_gl_format_from_video_info (params->parent.context,
1495             params->v_info, i);
1496       }
1497 
1498       params->plane = i;
1499       if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) {
1500         g_return_val_if_fail (wrapped_data != NULL, FALSE);
1501         params->parent.wrapped_data = wrapped_data[i];
1502       } else if (alloc_flags &
1503           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
1504         g_return_val_if_fail (wrapped_data != NULL, FALSE);
1505         params->parent.gl_handle = wrapped_data[i];
1506       }
1507 
1508       if (!(gl_mem = (GstGLMemory *) gst_gl_base_memory_alloc (base_allocator,
1509                   (GstGLAllocationParams *) params)))
1510         return FALSE;
1511 
1512       gst_buffer_append_memory (buffer, (GstMemory *) gl_mem);
1513     }
1514 
1515     meta = gst_buffer_add_video_meta_full (buffer, v,
1516         GST_VIDEO_INFO_FORMAT (params->v_info),
1517         GST_VIDEO_INFO_WIDTH (params->v_info),
1518         GST_VIDEO_INFO_HEIGHT (params->v_info), n_mem, params->v_info->offset,
1519         params->v_info->stride);
1520 
1521     if (params->valign)
1522       gst_video_meta_set_alignment (meta, *params->valign);
1523   }
1524 
1525   return TRUE;
1526 }
1527 
1528 /**
1529  * gst_gl_memory_allocator_get_default:
1530  * @context: a #GstGLContext
1531  *
1532  * Returns: (transfer full): the default #GstGLMemoryAllocator supported by
1533  *          @context
1534  *
1535  * Since: 1.8
1536  */
1537 GstGLMemoryAllocator *
gst_gl_memory_allocator_get_default(GstGLContext * context)1538 gst_gl_memory_allocator_get_default (GstGLContext * context)
1539 {
1540   GstGLMemoryAllocator *allocator = NULL;
1541 
1542   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1543 
1544   /* we can only use the pbo allocator with GL > 3.0 contexts */
1545   if (gst_gl_context_check_gl_version (context,
1546           GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2, 3, 0)) {
1547     allocator = (GstGLMemoryAllocator *)
1548         gst_allocator_find (GST_GL_MEMORY_PBO_ALLOCATOR_NAME);
1549   } else {
1550     allocator = (GstGLMemoryAllocator *)
1551         gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME);
1552   }
1553 
1554   return allocator;
1555 }
1556