3 * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
4 * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
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.
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.
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.
29 #include "gstglupload.h"
30 #include "gstglfuncs.h"
32 #if GST_GL_HAVE_PLATFORM_EGL
33 #include "egl/gsteglimage.h"
34 #include "egl/gsteglimage_private.h"
35 #include "egl/gstglmemoryegl.h"
36 #include "egl/gstglcontext_egl.h"
39 #if GST_GL_HAVE_DMABUF
40 #include <gst/allocators/gstdmabuf.h>
43 #if GST_GL_HAVE_VIV_DIRECTVIV
44 #include <gst/allocators/gstphysmemory.h>
45 #include <gst/gl/gstglfuncs.h>
51 * @short_description: an object that uploads to GL textures
52 * @see_also: #GstGLDownload, #GstGLMemory
54 * #GstGLUpload is an object that uploads data from system memory into GL textures.
56 * A #GstGLUpload can be created with gst_gl_upload_new()
59 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
60 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
61 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
62 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
63 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
65 GST_DEBUG_CATEGORY_STATIC (gst_gl_upload_debug);
66 #define GST_CAT_DEFAULT gst_gl_upload_debug
68 static void gst_gl_upload_finalize (GObject * object);
70 static GstGLTextureTarget
71 _caps_get_texture_target (GstCaps * caps, GstGLTextureTarget default_target)
73 GstGLTextureTarget ret = 0;
74 GstStructure *s = gst_caps_get_structure (caps, 0);
76 if (gst_structure_has_field_typed (s, "texture-target", G_TYPE_STRING)) {
77 const gchar *target_str = gst_structure_get_string (s, "texture-target");
78 ret = gst_gl_texture_target_from_string (target_str);
87 /* Define the maximum number of planes we can upload - handle 2 views per buffer */
88 #define GST_GL_UPLOAD_MAX_PLANES (GST_VIDEO_MAX_PLANES * 2)
90 typedef struct _UploadMethod UploadMethod;
92 struct _GstGLUploadPrivate
95 GstVideoInfo out_info;
101 /* all method impl pointers */
102 gpointer *upload_impl;
105 const UploadMethod *method;
106 gpointer method_impl;
109 /* saved method for reconfigure */
114 GST_DEBUG_CATEGORY_INIT (gst_gl_upload_debug, "glupload", 0, "upload");
116 G_DEFINE_TYPE_WITH_CODE (GstGLUpload, gst_gl_upload, GST_TYPE_OBJECT,
117 G_ADD_PRIVATE (GstGLUpload) DEBUG_INIT);
120 _set_caps_features_with_passthrough (const GstCaps * caps,
121 const gchar * feature_name, GstCapsFeatures * passthrough)
126 tmp = gst_caps_new_empty ();
128 n = gst_caps_get_size (caps);
129 for (i = 0; i < n; i++) {
130 GstCapsFeatures *features, *orig_features;
131 GstStructure *s = gst_caps_get_structure (caps, i);
133 orig_features = gst_caps_get_features (caps, i);
134 features = gst_caps_features_new (feature_name, NULL);
136 if (gst_caps_features_is_any (orig_features)) {
137 /* if we have any features, we add both the features with and without @passthrough */
138 gst_caps_append_structure_full (tmp, gst_structure_copy (s),
139 gst_caps_features_copy (features));
141 m = gst_caps_features_get_size (passthrough);
142 for (j = 0; j < m; j++) {
143 const gchar *feature = gst_caps_features_get_nth (passthrough, j);
145 /* if we already have the features */
146 if (gst_caps_features_contains (features, feature))
149 gst_caps_features_add (features, feature);
152 m = gst_caps_features_get_size (orig_features);
153 for (j = 0; j < m; j++) {
154 const gchar *feature = gst_caps_features_get_nth (orig_features, j);
156 /* if we already have the features */
157 if (gst_caps_features_contains (features, feature))
160 if (g_strcmp0 (feature, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) == 0)
163 if (gst_caps_features_contains (passthrough, feature)) {
164 gst_caps_features_add (features, feature);
169 gst_caps_append_structure_full (tmp, gst_structure_copy (s), features);
176 _caps_intersect_texture_target (GstCaps * caps, GstGLTextureTarget target_mask)
178 GValue targets = G_VALUE_INIT;
179 GstCaps *ret, *target;
181 target = gst_caps_copy (caps);
182 gst_gl_value_set_texture_target_from_mask (&targets, target_mask);
183 gst_caps_set_value (target, "texture-target", &targets);
185 ret = gst_caps_intersect_full (caps, target, GST_CAPS_INTERSECT_FIRST);
187 g_value_unset (&targets);
188 gst_caps_unref (target);
194 METHOD_FLAG_CAN_SHARE_CONTEXT = 1,
195 METHOD_FLAG_CAN_ACCEPT_RAW = 2, /* This method can accept raw memory input caps */
196 } GstGLUploadMethodFlags;
201 GstGLUploadMethodFlags flags;
203 GstStaticCaps *input_template_caps;
205 gpointer (*new) (GstGLUpload * upload);
206 GstCaps *(*transform_caps) (gpointer impl, GstGLContext * context,
207 GstPadDirection direction, GstCaps * caps);
208 gboolean (*accept) (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
210 void (*propose_allocation) (gpointer impl, GstQuery * decide_query,
212 GstGLUploadReturn (*perform) (gpointer impl, GstBuffer * buffer,
213 GstBuffer ** outbuf);
214 void (*free) (gpointer impl);
217 struct GLMemoryUpload
220 GstGLTextureTarget input_target;
221 GstGLTextureTarget output_target;
225 _gl_memory_upload_new (GstGLUpload * upload)
227 struct GLMemoryUpload *mem = g_new0 (struct GLMemoryUpload, 1);
229 mem->upload = upload;
230 mem->input_target = GST_GL_TEXTURE_TARGET_NONE;
231 mem->output_target = GST_GL_TEXTURE_TARGET_NONE;
237 _gl_memory_upload_transform_caps (gpointer impl, GstGLContext * context,
238 GstPadDirection direction, GstCaps * caps)
240 struct GLMemoryUpload *upload = impl;
241 GstCapsFeatures *passthrough =
242 gst_caps_features_from_string
243 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
247 _set_caps_features_with_passthrough (caps,
248 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
250 gst_caps_features_free (passthrough);
252 if (direction == GST_PAD_SINK) {
254 GstGLTextureTarget target_mask;
256 if (upload->input_target != GST_GL_TEXTURE_TARGET_NONE) {
257 target_mask = 1 << upload->input_target;
259 target_mask = 1 << GST_GL_TEXTURE_TARGET_2D |
260 1 << GST_GL_TEXTURE_TARGET_RECTANGLE |
261 1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
264 tmp = _caps_intersect_texture_target (ret, target_mask);
265 gst_caps_unref (ret);
270 n = gst_caps_get_size (ret);
271 for (i = 0; i < n; i++) {
272 GstStructure *s = gst_caps_get_structure (ret, i);
274 gst_structure_remove_fields (s, "texture-target", NULL);
282 _gl_memory_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
285 struct GLMemoryUpload *upload = impl;
286 GstCapsFeatures *features;
289 features = gst_caps_get_features (out_caps, 0);
290 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
293 features = gst_caps_get_features (in_caps, 0);
294 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)
295 && !gst_caps_features_contains (features,
296 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY))
300 GstVideoInfo *in_info = &upload->upload->priv->in_info;
301 guint expected_memories = GST_VIDEO_INFO_N_PLANES (in_info);
303 /* Support stereo views for separated multiview mode */
304 if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
305 GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
306 expected_memories *= GST_VIDEO_INFO_VIEWS (in_info);
308 if (gst_buffer_n_memory (buffer) != expected_memories)
311 for (i = 0; i < expected_memories; i++) {
312 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
314 if (!gst_is_gl_memory (mem))
323 _gl_memory_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
326 struct GLMemoryUpload *upload = impl;
327 GstBufferPool *pool = NULL;
330 GstCapsFeatures *features;
332 gst_query_parse_allocation (query, &caps, NULL);
335 features = gst_caps_get_features (caps, 0);
337 /* Only offer our custom allocator if that type of memory was negotiated. */
338 if (gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
339 GstAllocator *allocator;
340 GstAllocationParams params;
341 gst_allocation_params_init (¶ms);
344 GST_ALLOCATOR (gst_gl_memory_allocator_get_default (upload->
346 gst_query_add_allocation_param (query, allocator, ¶ms);
347 gst_object_unref (allocator);
349 #if GST_GL_HAVE_PLATFORM_EGL
350 if (upload->upload->context
351 && gst_gl_context_get_gl_platform (upload->upload->context) ==
352 GST_GL_PLATFORM_EGL) {
354 GST_ALLOCATOR (gst_allocator_find (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
355 gst_query_add_allocation_param (query, allocator, ¶ms);
356 gst_object_unref (allocator);
361 n_pools = gst_query_get_n_allocation_pools (query);
362 for (i = 0; i < n_pools; i++) {
363 gst_query_parse_nth_allocation_pool (query, i, &pool, NULL, NULL, NULL);
364 if (!GST_IS_GL_BUFFER_POOL (pool)) {
365 gst_object_unref (pool);
371 GstStructure *config;
376 if (!gst_video_info_from_caps (&info, caps))
379 pool = gst_gl_buffer_pool_new (upload->upload->context);
380 config = gst_buffer_pool_get_config (pool);
382 /* the normal size of a frame */
384 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
385 gst_buffer_pool_config_add_option (config,
386 GST_BUFFER_POOL_OPTION_GL_SYNC_META);
387 if (upload->upload->priv->out_caps) {
388 GstGLTextureTarget target;
389 const gchar *target_pool_option_str;
392 _caps_get_texture_target (upload->upload->priv->out_caps,
393 GST_GL_TEXTURE_TARGET_2D);
394 target_pool_option_str =
395 gst_gl_texture_target_to_buffer_pool_option (target);
396 gst_buffer_pool_config_add_option (config, target_pool_option_str);
399 if (!gst_buffer_pool_set_config (pool, config)) {
400 gst_object_unref (pool);
404 gst_query_add_allocation_pool (query, pool, size, 1, 0);
408 gst_object_unref (pool);
414 GST_WARNING_OBJECT (upload->upload, "invalid caps specified");
419 GST_WARNING_OBJECT (upload->upload, "failed setting config");
424 static GstGLUploadReturn
425 _gl_memory_upload_perform (gpointer impl, GstBuffer * buffer,
428 struct GLMemoryUpload *upload = impl;
432 n = gst_buffer_n_memory (buffer);
433 for (i = 0; i < n; i++) {
434 GstMemory *mem = gst_buffer_peek_memory (buffer, i);
436 gl_mem = (GstGLMemory *) mem;
437 if (!gst_gl_context_can_share (upload->upload->context,
438 gl_mem->mem.context))
439 return GST_GL_UPLOAD_UNSHARED_GL_CONTEXT;
441 if (upload->output_target == GST_GL_TEXTURE_TARGET_NONE &&
442 upload->upload->priv->out_caps) {
443 upload->output_target =
444 _caps_get_texture_target (upload->upload->priv->out_caps,
445 GST_GL_TEXTURE_TARGET_NONE);
448 /* always track the last input texture target so ::transform_caps() can
449 * use it to build the output caps */
450 upload->input_target = gl_mem->tex_target;
451 if (upload->output_target != gl_mem->tex_target) {
453 return GST_GL_UPLOAD_RECONFIGURE;
456 if (gst_is_gl_memory_pbo (mem))
457 gst_gl_memory_pbo_upload_transfer ((GstGLMemoryPBO *) mem);
460 *outbuf = gst_buffer_ref (buffer);
462 return GST_GL_UPLOAD_DONE;
466 _gl_memory_upload_free (gpointer impl)
472 static GstStaticCaps _gl_memory_upload_caps =
473 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
474 (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, GST_GL_MEMORY_VIDEO_FORMATS_STR));
476 static const UploadMethod _gl_memory_upload = {
478 METHOD_FLAG_CAN_SHARE_CONTEXT,
479 &_gl_memory_upload_caps,
480 &_gl_memory_upload_new,
481 &_gl_memory_upload_transform_caps,
482 &_gl_memory_upload_accept,
483 &_gl_memory_upload_propose_allocation,
484 &_gl_memory_upload_perform,
485 &_gl_memory_upload_free
488 #if GST_GL_HAVE_DMABUF
493 GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES];
494 GstGLFormat formats[GST_VIDEO_MAX_PLANES];
496 GstGLVideoAllocationParams *params;
500 GstGLTextureTarget target;
501 GstVideoInfo out_info;
502 /* only used for pointer comparison */
506 static GstStaticCaps _dma_buf_upload_caps =
507 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
508 (GST_CAPS_FEATURE_MEMORY_DMABUF,
509 GST_GL_MEMORY_VIDEO_FORMATS_STR) ";"
510 GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
513 _dma_buf_upload_new (GstGLUpload * upload)
515 struct DmabufUpload *dmabuf = g_new0 (struct DmabufUpload, 1);
516 dmabuf->upload = upload;
517 dmabuf->target = GST_GL_TEXTURE_TARGET_2D;
522 _dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
523 GstPadDirection direction, GstCaps * caps)
525 struct DmabufUpload *dmabuf = impl;
526 GstCapsFeatures *passthrough;
530 const GstGLFuncs *gl = context->gl_vtable;
532 if (!gl->EGLImageTargetTexture2D)
535 /* Don't propose DMABuf caps feature unless it can be supported */
536 if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
539 if (!gst_gl_context_check_feature (context, "EGL_KHR_image_base"))
543 passthrough = gst_caps_features_from_string
544 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
546 if (direction == GST_PAD_SINK) {
550 _set_caps_features_with_passthrough (caps,
551 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
553 tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
554 gst_caps_unref (ret);
560 _set_caps_features_with_passthrough (caps,
561 GST_CAPS_FEATURE_MEMORY_DMABUF, passthrough);
563 n = gst_caps_get_size (ret);
564 for (i = 0; i < n; i++) {
565 GstStructure *s = gst_caps_get_structure (ret, i);
567 gst_structure_remove_fields (s, "texture-target", NULL);
571 gst_caps_features_free (passthrough);
573 GST_DEBUG_OBJECT (dmabuf->upload, "transformed %" GST_PTR_FORMAT " into %"
574 GST_PTR_FORMAT, caps, ret);
580 _eglimage_quark (gint plane)
582 static GQuark quark[5] = { 0 };
583 static const gchar *quark_str[] = {
584 "GstGLDMABufEGLImage0",
585 "GstGLDMABufEGLImage1",
586 "GstGLDMABufEGLImage2",
587 "GstGLDMABufEGLImage3",
588 "GstGLDMABufEGLImage",
592 quark[plane] = g_quark_from_static_string (quark_str[plane]);
598 _get_cached_eglimage (GstMemory * mem, gint plane)
600 return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
601 _eglimage_quark (plane));
605 _set_cached_eglimage (GstMemory * mem, GstEGLImage * eglimage, gint plane)
607 return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
608 _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref);
612 _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
615 struct DmabufUpload *dmabuf = impl;
616 GstVideoInfo *in_info = &dmabuf->upload->priv->in_info;
617 GstVideoInfo *out_info = &dmabuf->out_info;
618 guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
621 GstMemory *mems[GST_VIDEO_MAX_PLANES];
622 gsize offset[GST_VIDEO_MAX_PLANES];
623 gint fd[GST_VIDEO_MAX_PLANES];
626 n_mem = gst_buffer_n_memory (buffer);
627 meta = gst_buffer_get_video_meta (buffer);
629 if (!dmabuf->upload->context->gl_vtable->EGLImageTargetTexture2D)
632 /* dmabuf upload is only supported with EGL contexts. */
633 if (gst_gl_context_get_gl_platform (dmabuf->upload->context) !=
637 if (!gst_gl_context_check_feature (dmabuf->upload->context,
638 "EGL_KHR_image_base")) {
639 GST_DEBUG_OBJECT (dmabuf->upload, "no EGL_KHR_image_base extension");
643 if (dmabuf->target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES &&
644 !gst_gl_context_check_feature (dmabuf->upload->context,
645 "GL_OES_EGL_image_external")) {
646 GST_DEBUG_OBJECT (dmabuf->upload, "no GL_OES_EGL_image_external extension");
650 /* This will eliminate most non-dmabuf out there */
651 if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0))) {
652 GST_DEBUG_OBJECT (dmabuf->upload, "input not dmabuf");
656 /* We cannot have multiple dmabuf per plane */
657 if (n_mem > n_planes) {
658 GST_DEBUG_OBJECT (dmabuf->upload,
659 "number of memory (%u) != number of planes (%u)", n_mem, n_planes);
663 /* Update video info based on video meta */
665 in_info->width = meta->width;
666 in_info->height = meta->height;
668 for (i = 0; i < meta->n_planes; i++) {
669 in_info->offset[i] = meta->offset[i];
670 in_info->stride[i] = meta->stride[i];
674 if (out_caps != dmabuf->out_caps) {
675 dmabuf->out_caps = out_caps;
676 if (!gst_video_info_from_caps (out_info, out_caps))
680 * When we zero-copy tiles, we need to propagate the strides, which contains
681 * the tile dimension. This is because the shader needs to know the padded
682 * size in order to correctly sample into these special buffer.
684 if (meta && GST_VIDEO_FORMAT_INFO_IS_TILED (out_info->finfo)) {
685 out_info->width = meta->width;
686 out_info->height = meta->height;
688 for (i = 0; i < meta->n_planes; i++) {
689 out_info->offset[i] = meta->offset[i];
690 out_info->stride[i] = meta->stride[i];
696 gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
697 if (!(dmabuf->params =
698 gst_gl_video_allocation_params_new_wrapped_gl_handle (dmabuf->
699 upload->context, NULL, out_info, -1, NULL, dmabuf->target, 0,
703 /* Find and validate all memories */
704 for (i = 0; i < n_planes; i++) {
710 plane_size = gst_gl_get_plane_data_size (in_info, NULL, i);
712 if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size,
713 &mem_idx, &length, &mem_skip)) {
714 GST_DEBUG_OBJECT (dmabuf->upload, "could not find memory %u", i);
718 /* We can't have more then one dmabuf per plane */
720 GST_DEBUG_OBJECT (dmabuf->upload, "data for plane %u spans %u memories",
725 mems[i] = gst_buffer_peek_memory (buffer, mem_idx);
727 /* And all memory found must be dmabuf */
728 if (!gst_is_dmabuf_memory (mems[i])) {
729 GST_DEBUG_OBJECT (dmabuf->upload, "memory %u is not dmabuf", i);
733 offset[i] = mems[i]->offset + mem_skip;
734 fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
737 if (dmabuf->direct) {
738 /* Check if this format is supported by the driver */
740 if (!gst_egl_image_check_dmabuf_direct (dmabuf->upload->context, in_info,
742 GST_DEBUG_OBJECT (dmabuf->upload, "direct check failed");
746 dmabuf->n_mem = n_planes;
748 /* Now create an EGLImage for each dmabufs */
749 for (i = 0; i < dmabuf->n_mem; i++) {
750 gint cache_id = dmabuf->direct ? 4 : i;
752 /* check if one is cached */
753 dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], cache_id);
754 if (dmabuf->eglimage[i]) {
755 dmabuf->formats[i] = dmabuf->eglimage[i]->format;
759 /* otherwise create one and cache it */
761 dmabuf->eglimage[i] =
762 gst_egl_image_from_dmabuf_direct_target (dmabuf->upload->context, fd,
763 offset, in_info, dmabuf->target);
765 dmabuf->eglimage[i] = gst_egl_image_from_dmabuf (dmabuf->upload->context,
766 fd[i], in_info, i, offset[i]);
768 if (!dmabuf->eglimage[i]) {
769 GST_DEBUG_OBJECT (dmabuf->upload, "could not create eglimage");
773 _set_cached_eglimage (mems[i], dmabuf->eglimage[i], cache_id);
774 dmabuf->formats[i] = dmabuf->eglimage[i]->format;
781 _dma_buf_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
784 /* nothing to do for now. */
788 _dma_buf_upload_perform_gl_thread (GstGLContext * context,
789 struct DmabufUpload *dmabuf)
791 GstGLMemoryAllocator *allocator;
794 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
795 (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
797 /* FIXME: buffer pool */
798 dmabuf->outbuf = gst_buffer_new ();
799 gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params,
800 dmabuf->formats, (gpointer *) dmabuf->eglimage, dmabuf->n_mem);
801 gst_object_unref (allocator);
804 static GstGLUploadReturn
805 _dma_buf_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
807 struct DmabufUpload *dmabuf = impl;
809 /* The direct path sets sinkpad caps to RGBA but this may be incorrect for
810 * the non-direct path, if that path fails to accept. In that case, we need
813 if (!dmabuf->direct &&
814 GST_VIDEO_INFO_FORMAT (&dmabuf->upload->priv->in_info) !=
815 GST_VIDEO_INFO_FORMAT (&dmabuf->out_info))
816 return GST_GL_UPLOAD_RECONFIGURE;
818 gst_gl_context_thread_add (dmabuf->upload->context,
819 (GstGLContextThreadFunc) _dma_buf_upload_perform_gl_thread, dmabuf);
822 return GST_GL_UPLOAD_ERROR;
824 gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer);
826 *outbuf = dmabuf->outbuf;
827 dmabuf->outbuf = NULL;
829 return GST_GL_UPLOAD_DONE;
833 _dma_buf_upload_free (gpointer impl)
835 struct DmabufUpload *dmabuf = impl;
838 gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
843 static const UploadMethod _dma_buf_upload = {
845 METHOD_FLAG_CAN_ACCEPT_RAW,
846 &_dma_buf_upload_caps,
847 &_dma_buf_upload_new,
848 &_dma_buf_upload_transform_caps,
849 &_dma_buf_upload_accept,
850 &_dma_buf_upload_propose_allocation,
851 &_dma_buf_upload_perform,
852 &_dma_buf_upload_free
855 /* a variant of the DMABuf uploader that relies on HW color conversion instead
859 _direct_dma_buf_upload_new (GstGLUpload * upload)
861 struct DmabufUpload *dmabuf = _dma_buf_upload_new (upload);
862 dmabuf->direct = TRUE;
863 gst_video_info_init (&dmabuf->out_info);
868 _direct_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
869 GstPadDirection direction, GstCaps * caps)
871 struct DmabufUpload *dmabuf = impl;
872 GstCapsFeatures *passthrough;
876 const GstGLFuncs *gl = context->gl_vtable;
878 if (!gl->EGLImageTargetTexture2D)
881 /* Don't propose direct DMABuf caps feature unless it can be supported */
882 if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
885 if (dmabuf->target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES &&
886 !gst_gl_context_check_feature (context, "GL_OES_EGL_image_external"))
890 passthrough = gst_caps_features_from_string
891 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
893 if (direction == GST_PAD_SINK) {
896 GstGLTextureTarget target_mask;
899 _set_caps_features_with_passthrough (caps,
900 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
902 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
904 n = gst_caps_get_size (ret);
905 for (i = 0; i < n; i++) {
906 GstStructure *s = gst_caps_get_structure (ret, i);
908 gst_structure_remove_fields (s, "chroma-site", NULL);
909 gst_structure_remove_fields (s, "colorimetry", NULL);
912 target_mask = 1 << dmabuf->target;
913 tmp = _caps_intersect_texture_target (ret, target_mask);
914 gst_caps_unref (ret);
919 GValue formats = G_VALUE_INIT;
920 gchar *format_str = g_strdup (GST_GL_MEMORY_VIDEO_FORMATS_STR);
923 _set_caps_features_with_passthrough (caps,
924 GST_CAPS_FEATURE_MEMORY_DMABUF, passthrough);
926 g_value_init (&formats, GST_TYPE_LIST);
927 gst_value_deserialize (&formats, format_str);
928 tmp = gst_caps_copy (ret);
929 gst_caps_set_value (tmp, "format", &formats);
930 gst_caps_append (ret, tmp);
932 g_value_unset (&formats);
934 n = gst_caps_get_size (ret);
935 for (i = 0; i < n; i++) {
936 GstStructure *s = gst_caps_get_structure (ret, i);
938 gst_structure_remove_fields (s, "texture-target", NULL);
942 gst_caps_features_free (passthrough);
944 GST_DEBUG_OBJECT (dmabuf->upload, "transformed %" GST_PTR_FORMAT " into %"
945 GST_PTR_FORMAT, caps, ret);
950 static const UploadMethod _direct_dma_buf_upload = {
952 METHOD_FLAG_CAN_ACCEPT_RAW,
953 &_dma_buf_upload_caps,
954 &_direct_dma_buf_upload_new,
955 &_direct_dma_buf_upload_transform_caps,
956 &_dma_buf_upload_accept,
957 &_dma_buf_upload_propose_allocation,
958 &_dma_buf_upload_perform,
959 &_dma_buf_upload_free
962 /* a variant of the direct DMABuf uploader that uses external OES textures */
965 _direct_dma_buf_external_upload_new (GstGLUpload * upload)
967 struct DmabufUpload *dmabuf = _direct_dma_buf_upload_new (upload);
968 dmabuf->target = GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
972 static const UploadMethod _direct_dma_buf_external_upload = {
973 "DirectDmabufExternal",
974 METHOD_FLAG_CAN_ACCEPT_RAW,
975 &_dma_buf_upload_caps,
976 &_direct_dma_buf_external_upload_new,
977 &_direct_dma_buf_upload_transform_caps,
978 &_dma_buf_upload_accept,
979 &_dma_buf_upload_propose_allocation,
980 &_dma_buf_upload_perform,
981 &_dma_buf_upload_free
984 #endif /* GST_GL_HAVE_DMABUF */
991 GstVideoGLTextureUploadMeta *meta;
992 guint texture_ids[GST_GL_UPLOAD_MAX_PLANES];
997 _upload_meta_upload_new (GstGLUpload * upload)
999 struct GLUploadMeta *meta = g_new0 (struct GLUploadMeta, 1);
1001 meta->upload = upload;
1008 _upload_meta_upload_transform_caps (gpointer impl, GstGLContext * context,
1009 GstPadDirection direction, GstCaps * caps)
1011 GstCapsFeatures *passthrough =
1012 gst_caps_features_from_string
1013 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1016 if (direction == GST_PAD_SINK) {
1020 _set_caps_features_with_passthrough (caps,
1021 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1023 tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
1024 gst_caps_unref (ret);
1030 _set_caps_features_with_passthrough (caps,
1031 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, passthrough);
1032 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
1034 n = gst_caps_get_size (ret);
1035 for (i = 0; i < n; i++) {
1036 GstStructure *s = gst_caps_get_structure (ret, i);
1038 gst_structure_remove_fields (s, "texture-target", NULL);
1042 gst_caps_features_free (passthrough);
1048 _upload_meta_upload_accept (gpointer impl, GstBuffer * buffer,
1049 GstCaps * in_caps, GstCaps * out_caps)
1051 struct GLUploadMeta *upload = impl;
1052 GstCapsFeatures *features;
1053 GstVideoGLTextureUploadMeta *meta;
1054 gboolean ret = TRUE;
1055 GstStructure *config;
1058 features = gst_caps_get_features (in_caps, 0);
1060 if (!gst_caps_features_contains (features,
1061 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META))
1064 features = gst_caps_get_features (out_caps, 0);
1065 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1071 if (upload->pool == NULL)
1072 upload->pool = gst_gl_buffer_pool_new (upload->upload->context);
1074 if (!gst_buffer_pool_is_active (upload->pool)) {
1075 config = gst_buffer_pool_get_config (upload->pool);
1077 size = upload->upload->priv->in_info.size;
1078 gst_buffer_pool_config_set_params (config, in_caps, size, 0, 0);
1080 if (!gst_buffer_pool_set_config (upload->pool, config)) {
1081 GST_WARNING_OBJECT (upload->upload, "failed to set bufferpool config");
1084 gst_buffer_pool_set_active (upload->pool, TRUE);
1088 if ((meta = gst_buffer_get_video_gl_texture_upload_meta (buffer)) == NULL)
1091 if (meta->texture_type[0] != GST_VIDEO_GL_TEXTURE_TYPE_RGBA) {
1092 GST_FIXME_OBJECT (upload, "only single rgba texture supported");
1096 if (meta->texture_orientation !=
1097 GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL) {
1098 GST_FIXME_OBJECT (upload, "only x-normal, y-normal textures supported");
1107 _upload_meta_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1110 struct GLUploadMeta *upload = impl;
1111 GstStructure *gl_context;
1112 gchar *platform, *gl_apis;
1116 gst_gl_api_to_string (gst_gl_context_get_gl_api (upload->upload->
1119 gst_gl_platform_to_string (gst_gl_context_get_gl_platform (upload->
1121 handle = (gpointer) gst_gl_context_get_gl_context (upload->upload->context);
1124 gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
1125 GST_TYPE_GL_CONTEXT, upload->upload->context, "gst.gl.context.handle",
1126 G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
1127 "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
1128 gst_query_add_allocation_meta (query,
1129 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
1133 gst_structure_free (gl_context);
1137 * Uploads using gst_video_gl_texture_upload_meta_upload().
1138 * i.e. consumer of GstVideoGLTextureUploadMeta
1141 _do_upload_with_meta (GstGLContext * context, struct GLUploadMeta *upload)
1143 if (!gst_video_gl_texture_upload_meta_upload (upload->meta,
1144 upload->texture_ids)) {
1145 upload->result = FALSE;
1149 upload->result = TRUE;
1152 static GstGLUploadReturn
1153 _upload_meta_upload_perform (gpointer impl, GstBuffer * buffer,
1154 GstBuffer ** outbuf)
1156 struct GLUploadMeta *upload = impl;
1158 GstVideoInfo *in_info = &upload->upload->priv->in_info;
1159 guint max_planes = GST_VIDEO_INFO_N_PLANES (in_info);
1161 /* Support stereo views for separated multiview mode */
1162 if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
1163 GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
1164 max_planes *= GST_VIDEO_INFO_VIEWS (in_info);
1166 GST_LOG_OBJECT (upload, "Attempting upload with GstVideoGLTextureUploadMeta");
1168 upload->meta = gst_buffer_get_video_gl_texture_upload_meta (buffer);
1170 if (gst_buffer_pool_acquire_buffer (upload->pool, outbuf,
1171 NULL) != GST_FLOW_OK) {
1172 GST_WARNING_OBJECT (upload, "failed to acquire buffer from bufferpool");
1173 return GST_GL_UPLOAD_ERROR;
1176 for (i = 0; i < GST_GL_UPLOAD_MAX_PLANES; i++) {
1179 if (i < max_planes) {
1180 GstMemory *mem = gst_buffer_peek_memory (*outbuf, i);
1181 tex_id = ((GstGLMemory *) mem)->tex_id;
1184 upload->texture_ids[i] = tex_id;
1187 GST_LOG ("Uploading with GLTextureUploadMeta with textures "
1188 "%i,%i,%i,%i / %i,%i,%i,%i",
1189 upload->texture_ids[0], upload->texture_ids[1],
1190 upload->texture_ids[2], upload->texture_ids[3],
1191 upload->texture_ids[4], upload->texture_ids[5],
1192 upload->texture_ids[6], upload->texture_ids[7]);
1194 gst_gl_context_thread_add (upload->upload->context,
1195 (GstGLContextThreadFunc) _do_upload_with_meta, upload);
1197 if (!upload->result)
1198 return GST_GL_UPLOAD_ERROR;
1200 return GST_GL_UPLOAD_DONE;
1204 _upload_meta_upload_free (gpointer impl)
1206 struct GLUploadMeta *upload = impl;
1208 g_return_if_fail (impl != NULL);
1211 gst_object_unref (upload->pool);
1216 static GstStaticCaps _upload_meta_upload_caps =
1217 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1218 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA"));
1220 static const UploadMethod _upload_meta_upload = {
1222 METHOD_FLAG_CAN_SHARE_CONTEXT,
1223 &_upload_meta_upload_caps,
1224 &_upload_meta_upload_new,
1225 &_upload_meta_upload_transform_caps,
1226 &_upload_meta_upload_accept,
1227 &_upload_meta_upload_propose_allocation,
1228 &_upload_meta_upload_perform,
1229 &_upload_meta_upload_free
1232 struct RawUploadFrame
1235 GstVideoFrame frame;
1240 GstGLUpload *upload;
1241 struct RawUploadFrame *in_frame;
1242 GstGLVideoAllocationParams *params;
1245 static struct RawUploadFrame *
1246 _raw_upload_frame_new (struct RawUpload *raw, GstBuffer * buffer)
1248 struct RawUploadFrame *frame;
1255 frame = g_slice_new (struct RawUploadFrame);
1256 frame->ref_count = 1;
1258 if (!gst_video_frame_map (&frame->frame, &raw->upload->priv->in_info,
1259 buffer, GST_MAP_READ)) {
1260 g_slice_free (struct RawUploadFrame, frame);
1264 raw->upload->priv->in_info = frame->frame.info;
1265 info = &raw->upload->priv->in_info;
1267 /* Recalculate the offsets (and size) */
1269 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1270 info->offset[i] = info->size;
1271 info->size += gst_gl_get_plane_data_size (info, NULL, i);
1278 _raw_upload_frame_ref (struct RawUploadFrame *frame)
1280 g_atomic_int_inc (&frame->ref_count);
1284 _raw_upload_frame_unref (struct RawUploadFrame *frame)
1286 if (g_atomic_int_dec_and_test (&frame->ref_count)) {
1287 gst_video_frame_unmap (&frame->frame);
1288 g_slice_free (struct RawUploadFrame, frame);
1293 _raw_data_upload_new (GstGLUpload * upload)
1295 struct RawUpload *raw = g_new0 (struct RawUpload, 1);
1297 raw->upload = upload;
1303 _raw_data_upload_transform_caps (gpointer impl, GstGLContext * context,
1304 GstPadDirection direction, GstCaps * caps)
1306 GstCapsFeatures *passthrough =
1307 gst_caps_features_from_string
1308 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1311 if (direction == GST_PAD_SINK) {
1312 GstGLTextureTarget target_mask = 0;
1316 _set_caps_features_with_passthrough (caps,
1317 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1319 target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D;
1320 target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE;
1321 tmp = _caps_intersect_texture_target (ret, target_mask);
1322 gst_caps_unref (ret);
1328 _set_caps_features_with_passthrough (caps,
1329 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
1331 n = gst_caps_get_size (ret);
1332 for (i = 0; i < n; i++) {
1333 GstStructure *s = gst_caps_get_structure (ret, i);
1335 gst_structure_remove_fields (s, "texture-target", NULL);
1339 gst_caps_features_free (passthrough);
1345 _raw_data_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1348 struct RawUpload *raw = impl;
1349 GstCapsFeatures *features;
1351 features = gst_caps_get_features (out_caps, 0);
1352 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1356 _raw_upload_frame_unref (raw->in_frame);
1357 raw->in_frame = _raw_upload_frame_new (raw, buffer);
1360 gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1362 gst_gl_video_allocation_params_new_wrapped_data (raw->upload->context,
1363 NULL, &raw->upload->priv->in_info, -1, NULL,
1364 GST_GL_TEXTURE_TARGET_2D, 0, NULL, raw->in_frame,
1365 (GDestroyNotify) _raw_upload_frame_unref)))
1368 return (raw->in_frame != NULL);
1372 _raw_data_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1375 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
1378 static GstGLUploadReturn
1379 _raw_data_upload_perform (gpointer impl, GstBuffer * buffer,
1380 GstBuffer ** outbuf)
1382 GstGLBaseMemoryAllocator *allocator;
1383 struct RawUpload *raw = impl;
1385 GstVideoInfo *in_info = &raw->upload->priv->in_info;
1386 guint n_mem = GST_VIDEO_INFO_N_PLANES (in_info);
1389 GST_GL_BASE_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_default
1390 (raw->upload->context));
1392 /* FIXME Use a buffer pool to cache the generated textures */
1393 *outbuf = gst_buffer_new ();
1394 raw->params->parent.context = raw->upload->context;
1395 if (gst_gl_memory_setup_buffer ((GstGLMemoryAllocator *) allocator, *outbuf,
1396 raw->params, NULL, raw->in_frame->frame.data, n_mem)) {
1398 for (i = 0; i < n_mem; i++)
1399 _raw_upload_frame_ref (raw->in_frame);
1400 gst_buffer_add_gl_sync_meta (raw->upload->context, *outbuf);
1402 GST_ERROR_OBJECT (raw->upload, "Failed to allocate wrapped texture");
1403 gst_buffer_unref (*outbuf);
1404 gst_object_unref (allocator);
1405 return GST_GL_UPLOAD_ERROR;
1407 gst_object_unref (allocator);
1408 _raw_upload_frame_unref (raw->in_frame);
1409 raw->in_frame = NULL;
1411 return GST_GL_UPLOAD_DONE;
1415 _raw_data_upload_free (gpointer impl)
1417 struct RawUpload *raw = impl;
1420 gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1425 static GstStaticCaps _raw_data_upload_caps =
1426 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
1428 static const UploadMethod _raw_data_upload = {
1431 &_raw_data_upload_caps,
1432 &_raw_data_upload_new,
1433 &_raw_data_upload_transform_caps,
1434 &_raw_data_upload_accept,
1435 &_raw_data_upload_propose_allocation,
1436 &_raw_data_upload_perform,
1437 &_raw_data_upload_free
1440 #if GST_GL_HAVE_VIV_DIRECTVIV
1442 #define GL_BGRA_EXT 0x80E1
1445 #define GL_VIV_YV12 0x8FC0
1448 #define GL_VIV_NV12 0x8FC1
1451 #define GL_VIV_YUY2 0x8FC2
1454 #define GL_VIV_UYVY 0x8FC3
1457 #define GL_VIV_NV21 0x8FC4
1460 #define GL_VIV_I420 0x8FC5
1463 struct DirectVIVUpload
1465 GstGLUpload *upload;
1467 GstGLVideoAllocationParams *params;
1468 GstBuffer *inbuf, *outbuf;
1469 void (*TexDirectVIVMap) (GLenum Target, GLsizei Width, GLsizei Height,
1470 GLenum Format, GLvoid ** Logical, const GLuint * Physical);
1471 void (*TexDirectInvalidateVIV) (GLenum Target);
1472 gboolean loaded_functions;
1475 #define GST_GL_DIRECTVIV_FORMAT "{RGBA, I420, YV12, NV12, NV21, YUY2, UYVY, BGRA, RGB16}"
1477 static GstStaticCaps _directviv_upload_caps =
1478 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DIRECTVIV_FORMAT));
1481 _directviv_upload_new (GstGLUpload * upload)
1483 struct DirectVIVUpload *directviv = g_new0 (struct DirectVIVUpload, 1);
1484 directviv->upload = upload;
1485 directviv->loaded_functions = FALSE;
1491 _directviv_upload_transform_caps (gpointer impl, GstGLContext * context,
1492 GstPadDirection direction, GstCaps * caps)
1494 GstCapsFeatures *passthrough =
1495 gst_caps_features_from_string
1496 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1499 if (direction == GST_PAD_SINK) {
1503 _set_caps_features_with_passthrough (caps,
1504 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1506 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
1507 tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
1508 gst_caps_unref (ret);
1511 ret = gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1512 (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, GST_GL_DIRECTVIV_FORMAT));
1515 gst_caps_features_free (passthrough);
1521 _directviv_upload_load_functions_gl_thread (GstGLContext * context,
1522 struct DirectVIVUpload *directviv)
1524 directviv->TexDirectVIVMap =
1525 gst_gl_context_get_proc_address (context, "glTexDirectVIVMap");
1526 directviv->TexDirectInvalidateVIV =
1527 gst_gl_context_get_proc_address (context, "glTexDirectInvalidateVIV");
1531 _directviv_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1534 struct DirectVIVUpload *directviv = impl;
1535 GstCapsFeatures *features;
1539 if (!directviv->loaded_functions && (!directviv->TexDirectInvalidateVIV ||
1540 !directviv->TexDirectVIVMap)) {
1541 gst_gl_context_thread_add (directviv->upload->context,
1542 (GstGLContextThreadFunc) _directviv_upload_load_functions_gl_thread,
1544 directviv->loaded_functions = TRUE;
1546 if (!directviv->TexDirectInvalidateVIV || !directviv->TexDirectVIVMap)
1549 features = gst_caps_get_features (out_caps, 0);
1550 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1553 if (directviv->params)
1554 gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1555 if (!(directviv->params =
1556 gst_gl_video_allocation_params_new (directviv->upload->context, NULL,
1557 &directviv->upload->priv->out_info, -1, NULL,
1558 GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA)))
1561 /* We only support a single memory per buffer at this point */
1562 n_mem = gst_buffer_n_memory (buffer);
1564 mem = gst_buffer_peek_memory (buffer, 0);
1569 return n_mem == 1 && mem && gst_is_phys_memory (mem);
1573 _directviv_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1579 _directviv_upload_video_format_to_gl_format (GstVideoFormat format)
1582 case GST_VIDEO_FORMAT_I420:
1584 case GST_VIDEO_FORMAT_YV12:
1586 case GST_VIDEO_FORMAT_NV12:
1588 case GST_VIDEO_FORMAT_NV21:
1590 case GST_VIDEO_FORMAT_YUY2:
1592 case GST_VIDEO_FORMAT_UYVY:
1594 case GST_VIDEO_FORMAT_RGB16:
1596 case GST_VIDEO_FORMAT_RGBA:
1598 case GST_VIDEO_FORMAT_BGRA:
1600 case GST_VIDEO_FORMAT_RGBx:
1602 case GST_VIDEO_FORMAT_BGRx:
1615 } DirectVIVUnmapData;
1618 _directviv_memory_unmap (DirectVIVUnmapData * data)
1620 gst_memory_unmap (data->memory, &data->map);
1621 gst_memory_unref (data->memory);
1622 gst_buffer_unref (data->buffer);
1627 _directviv_upload_perform_gl_thread (GstGLContext * context,
1628 struct DirectVIVUpload *directviv)
1630 static GQuark directviv_unmap_quark = 0;
1631 GstGLMemoryAllocator *allocator;
1633 GstGLMemory *out_gl_mem;
1634 GstVideoInfo *in_info;
1635 DirectVIVUnmapData *unmap_data;
1636 GstVideoMeta *vmeta;
1637 gint width, height, gl_format;
1638 const GstGLFuncs *gl;
1640 if (!directviv_unmap_quark)
1641 directviv_unmap_quark = g_quark_from_static_string ("GstGLDirectVIVUnmap");
1643 gl = context->gl_vtable;
1645 g_assert (gst_buffer_n_memory (directviv->inbuf) == 1);
1646 in_info = &directviv->upload->priv->in_info;
1647 in_mem = gst_buffer_peek_memory (directviv->inbuf, 0);
1648 unmap_data = g_new0 (DirectVIVUnmapData, 1);
1649 if (!gst_memory_map (in_mem, &unmap_data->map, GST_MAP_READ)) {
1650 g_free (unmap_data);
1653 unmap_data->phys_addr = gst_phys_memory_get_phys_addr (in_mem);
1654 if (!unmap_data->phys_addr) {
1655 gst_memory_unmap (in_mem, &unmap_data->map);
1656 g_free (unmap_data);
1659 unmap_data->memory = gst_memory_ref (in_mem);
1660 unmap_data->buffer = gst_buffer_ref (directviv->inbuf);
1663 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
1664 (GST_GL_MEMORY_PBO_ALLOCATOR_NAME));
1666 /* FIXME: buffer pool */
1667 directviv->outbuf = gst_buffer_new ();
1668 gst_gl_memory_setup_buffer (allocator, directviv->outbuf, directviv->params,
1670 gst_object_unref (allocator);
1672 out_gl_mem = (GstGLMemory *) gst_buffer_peek_memory (directviv->outbuf, 0);
1674 /* Need to keep the input memory and buffer mapped and valid until
1675 * the GL memory is not used anymore */
1676 gst_mini_object_set_qdata ((GstMiniObject *) out_gl_mem,
1677 directviv_unmap_quark, unmap_data,
1678 (GDestroyNotify) _directviv_memory_unmap);
1679 gst_buffer_add_parent_buffer_meta (directviv->outbuf, directviv->inbuf);
1681 /* width/height need to compensate for stride/padding */
1682 vmeta = gst_buffer_get_video_meta (directviv->inbuf);
1684 width = vmeta->stride[0];
1685 if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1686 height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1688 height = vmeta->offset[1] / width;
1690 width = GST_VIDEO_INFO_PLANE_STRIDE (in_info, 0);
1691 if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1692 height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1694 height = GST_VIDEO_INFO_PLANE_OFFSET (in_info, 1) / width;
1696 width /= GST_VIDEO_INFO_COMP_PSTRIDE (in_info, 0);
1699 _directviv_upload_video_format_to_gl_format (GST_VIDEO_INFO_FORMAT
1702 gl->BindTexture (GL_TEXTURE_2D, out_gl_mem->tex_id);
1703 directviv->TexDirectVIVMap (GL_TEXTURE_2D, width, height,
1704 gl_format, (void **) &unmap_data->map.data, &unmap_data->phys_addr);
1705 directviv->TexDirectInvalidateVIV (GL_TEXTURE_2D);
1708 static GstGLUploadReturn
1709 _directviv_upload_perform (gpointer impl, GstBuffer * buffer,
1710 GstBuffer ** outbuf)
1712 struct DirectVIVUpload *directviv = impl;
1714 directviv->inbuf = buffer;
1715 directviv->outbuf = NULL;
1716 gst_gl_context_thread_add (directviv->upload->context,
1717 (GstGLContextThreadFunc) _directviv_upload_perform_gl_thread, directviv);
1718 directviv->inbuf = NULL;
1720 if (!directviv->outbuf)
1721 return GST_GL_UPLOAD_ERROR;
1723 *outbuf = directviv->outbuf;
1724 directviv->outbuf = NULL;
1726 return GST_GL_UPLOAD_DONE;
1730 _directviv_upload_free (gpointer impl)
1732 struct DirectVIVUpload *directviv = impl;
1734 if (directviv->params)
1735 gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1740 static const UploadMethod _directviv_upload = {
1743 &_directviv_upload_caps,
1744 &_directviv_upload_new,
1745 &_directviv_upload_transform_caps,
1746 &_directviv_upload_accept,
1747 &_directviv_upload_propose_allocation,
1748 &_directviv_upload_perform,
1749 &_directviv_upload_free
1752 #endif /* GST_GL_HAVE_VIV_DIRECTVIV */
1754 #if defined(HAVE_NVMM)
1755 #include "nvbuf_utils.h"
1759 GstGLUpload *upload;
1761 GstGLVideoAllocationParams *params;
1764 GstGLTextureTarget target;
1765 GstVideoInfo out_info;
1766 /* only used for pointer comparison */
1770 #define GST_CAPS_FEATURE_MEMORY_NVMM "memory:NVMM"
1772 /* FIXME: other formats? */
1773 static GstStaticCaps _nvmm_upload_caps =
1774 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1775 (GST_CAPS_FEATURE_MEMORY_NVMM,
1779 _nvmm_upload_new (GstGLUpload * upload)
1781 struct NVMMUpload *nvmm = g_new0 (struct NVMMUpload, 1);
1782 nvmm->upload = upload;
1783 nvmm->target = GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
1788 _nvmm_upload_transform_caps (gpointer impl, GstGLContext * context,
1789 GstPadDirection direction, GstCaps * caps)
1791 struct NVMMUpload *nvmm = impl;
1792 GstCapsFeatures *passthrough;
1796 const GstGLFuncs *gl = context->gl_vtable;
1798 if (!gl->EGLImageTargetTexture2D)
1801 /* Don't propose NVMM caps feature unless it can be supported */
1802 if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
1805 if (!gst_gl_context_check_feature (context, "EGL_KHR_image_base"))
1809 passthrough = gst_caps_features_from_string
1810 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1812 if (direction == GST_PAD_SINK) {
1816 _set_caps_features_with_passthrough (caps,
1817 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1820 _caps_intersect_texture_target (ret,
1821 1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES);
1822 gst_caps_unref (ret);
1828 _set_caps_features_with_passthrough (caps,
1829 GST_CAPS_FEATURE_MEMORY_NVMM, passthrough);
1831 n = gst_caps_get_size (ret);
1832 for (i = 0; i < n; i++) {
1833 GstStructure *s = gst_caps_get_structure (ret, i);
1835 gst_structure_remove_fields (s, "texture-target", NULL);
1839 gst_caps_features_free (passthrough);
1841 GST_DEBUG_OBJECT (nvmm->upload, "transformed %" GST_PTR_FORMAT " into %"
1842 GST_PTR_FORMAT, caps, ret);
1848 _nvmm_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1851 struct NVMMUpload *nvmm = impl;
1852 GstVideoInfo *in_info = &nvmm->upload->priv->in_info;
1853 GstVideoInfo *out_info = &nvmm->out_info;
1855 GstMapInfo in_map_info = GST_MAP_INFO_INIT;
1859 n_mem = gst_buffer_n_memory (buffer);
1861 GST_DEBUG_OBJECT (nvmm->upload, "NVMM uploader only supports "
1862 "1 memory, not %u", n_mem);
1866 meta = gst_buffer_get_video_meta (buffer);
1868 if (!nvmm->upload->context->gl_vtable->EGLImageTargetTexture2D)
1871 /* NVMM upload is only supported with EGL contexts. */
1872 if (gst_gl_context_get_gl_platform (nvmm->upload->context) !=
1873 GST_GL_PLATFORM_EGL)
1876 if (!gst_gl_context_check_feature (nvmm->upload->context,
1877 "EGL_KHR_image_base"))
1880 if (!gst_buffer_map (buffer, &in_map_info, GST_MAP_READ)) {
1881 GST_DEBUG_OBJECT (nvmm->upload, "Failed to map readonly NvBuffer");
1884 if (in_map_info.size != NvBufferGetSize ()) {
1885 GST_DEBUG_OBJECT (nvmm->upload, "Memory size (%" G_GSIZE_FORMAT ") is "
1886 "not the same as what NvBuffer advertises (%u)", in_map_info.size,
1887 NvBufferGetSize ());
1888 gst_buffer_unmap (buffer, &in_map_info);
1891 gst_buffer_unmap (buffer, &in_map_info);
1893 /* Update video info based on video meta */
1895 in_info->width = meta->width;
1896 in_info->height = meta->height;
1898 for (i = 0; i < meta->n_planes; i++) {
1899 in_info->offset[i] = meta->offset[i];
1900 in_info->stride[i] = meta->stride[i];
1904 if (out_caps != nvmm->out_caps) {
1905 nvmm->out_caps = out_caps;
1906 if (!gst_video_info_from_caps (out_info, out_caps))
1911 gst_gl_allocation_params_free ((GstGLAllocationParams *) nvmm->params);
1912 if (!(nvmm->params =
1913 gst_gl_video_allocation_params_new_wrapped_gl_handle (nvmm->
1914 upload->context, NULL, out_info, -1, NULL, nvmm->target, 0, NULL,
1923 _nvmm_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1926 /* nothing to do for now. */
1930 _egl_image_mem_unref (GstEGLImage * image, GstMemory * mem)
1932 GstGLDisplayEGL *egl_display = NULL;
1935 egl_display = gst_gl_display_egl_from_gl_display (image->context->display);
1937 GST_ERROR ("Could not retrieve GstGLDisplayEGL from GstGLDisplay");
1941 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display));
1943 if (NvDestroyEGLImage (display, image->image)) {
1944 GST_ERROR ("Failed to destroy EGLImage %p from NvBuffer", image->image);
1946 GST_DEBUG ("destroyed EGLImage %p from NvBuffer", image->image);
1949 gst_memory_unref (mem);
1950 gst_object_unref (egl_display);
1954 payload_type_to_string (NvBufferPayloadType ptype)
1957 case NvBufferPayload_SurfArray:
1959 case NvBufferPayload_MemHandle:
1967 pixel_format_to_string (NvBufferColorFormat fmt)
1970 case NvBufferColorFormat_YUV420:
1972 case NvBufferColorFormat_YVU420:
1974 case NvBufferColorFormat_YUV422:
1976 case NvBufferColorFormat_YUV420_ER:
1978 case NvBufferColorFormat_YVU420_ER:
1980 case NvBufferColorFormat_NV12:
1982 case NvBufferColorFormat_NV12_ER:
1984 case NvBufferColorFormat_NV21:
1986 case NvBufferColorFormat_NV21_ER:
1988 case NvBufferColorFormat_UYVY:
1990 case NvBufferColorFormat_UYVY_ER:
1992 case NvBufferColorFormat_VYUY:
1994 case NvBufferColorFormat_VYUY_ER:
1996 case NvBufferColorFormat_YUYV:
1998 case NvBufferColorFormat_YUYV_ER:
2000 case NvBufferColorFormat_YVYU:
2002 case NvBufferColorFormat_YVYU_ER:
2004 case NvBufferColorFormat_ABGR32:
2006 case NvBufferColorFormat_XRGB32:
2008 case NvBufferColorFormat_ARGB32:
2010 case NvBufferColorFormat_NV12_10LE:
2012 case NvBufferColorFormat_NV12_10LE_709:
2013 return "NV12_10LE_709";
2014 case NvBufferColorFormat_NV12_10LE_709_ER:
2015 return "NV12_10LE_709_ER";
2016 case NvBufferColorFormat_NV12_10LE_2020:
2018 case NvBufferColorFormat_NV21_10LE:
2020 case NvBufferColorFormat_NV12_12LE:
2022 case NvBufferColorFormat_NV12_12LE_2020:
2023 return "NV12_12LE_2020";
2024 case NvBufferColorFormat_NV21_12LE:
2026 case NvBufferColorFormat_YUV420_709:
2027 return "YUV420_709";
2028 case NvBufferColorFormat_YUV420_709_ER:
2029 return "YUV420_709_ER";
2030 case NvBufferColorFormat_NV12_709:
2032 case NvBufferColorFormat_NV12_709_ER:
2033 return "NV12_709_ER";
2034 case NvBufferColorFormat_YUV420_2020:
2035 return "YUV420_2020";
2036 case NvBufferColorFormat_NV12_2020:
2038 case NvBufferColorFormat_SignedR16G16:
2039 return "SignedR16G16";
2040 case NvBufferColorFormat_A32:
2042 case NvBufferColorFormat_YUV444:
2044 case NvBufferColorFormat_GRAY8:
2046 case NvBufferColorFormat_NV16:
2048 case NvBufferColorFormat_NV16_10LE:
2050 case NvBufferColorFormat_NV24:
2052 case NvBufferColorFormat_NV16_ER:
2054 case NvBufferColorFormat_NV24_ER:
2056 case NvBufferColorFormat_NV16_709:
2058 case NvBufferColorFormat_NV24_709:
2060 case NvBufferColorFormat_NV16_709_ER:
2061 return "NV16_709_ER";
2062 case NvBufferColorFormat_NV24_709_ER:
2063 return "NV24_709_ER";
2064 case NvBufferColorFormat_NV24_10LE_709:
2065 return "NV24_10LE_709";
2066 case NvBufferColorFormat_NV24_10LE_709_ER:
2067 return "NV24_10LE_709_ER";
2068 case NvBufferColorFormat_NV24_10LE_2020:
2069 return "NV24_10LE_2020";
2070 case NvBufferColorFormat_NV24_12LE_2020:
2071 return "NV24_12LE_2020";
2072 case NvBufferColorFormat_RGBA_10_10_10_2_709:
2073 return "RGBA_10_10_10_2_709";
2074 case NvBufferColorFormat_RGBA_10_10_10_2_2020:
2075 return "RGBA_10_10_10_2_2020";
2076 case NvBufferColorFormat_BGRA_10_10_10_2_709:
2077 return "BGRA_10_10_10_2_709";
2078 case NvBufferColorFormat_BGRA_10_10_10_2_2020:
2079 return "BGRA_10_10_10_2_2020";
2080 case NvBufferColorFormat_Invalid:
2088 dump_nv_buf_params (GstObject * debug_object, NvBufferParamsEx * params)
2090 GST_DEBUG_OBJECT (debug_object, "nvbuffer fd: %u size %i nv_buffer: %p of "
2091 "size %u, payload: (0x%x) %s, pixel format: (0x%x) %s, n_planes: %u, "
2092 "plane 0 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u } "
2093 "plane 1 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u } "
2094 "plane 2 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u }",
2095 params->params.dmabuf_fd, params->params.memsize,
2096 params->params.nv_buffer, params->params.nv_buffer_size,
2097 params->params.payloadType,
2098 payload_type_to_string (params->params.payloadType),
2099 params->params.pixel_format,
2100 pixel_format_to_string (params->params.pixel_format),
2101 params->params.num_planes, params->params.width[0],
2102 params->params.height[0], params->params.pitch[0],
2103 params->params.offset[0], params->params.psize[0],
2104 params->params.offset[0], params->params.width[1],
2105 params->params.height[1], params->params.pitch[1],
2106 params->params.offset[1], params->params.psize[1],
2107 params->params.offset[1], params->params.width[2],
2108 params->params.height[2], params->params.pitch[2],
2109 params->params.offset[2], params->params.psize[2],
2110 params->params.offset[2]);
2113 static GstGLUploadReturn
2114 _nvmm_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
2116 struct NVMMUpload *nvmm = impl;
2117 GstGLMemoryAllocator *allocator = NULL;
2118 GstMapInfo in_map_info = GST_MAP_INFO_INIT;
2119 GstGLDisplayEGL *egl_display = NULL;
2120 GstEGLImage *eglimage = NULL;
2121 EGLDisplay display = EGL_NO_DISPLAY;
2122 EGLImageKHR image = EGL_NO_IMAGE;
2124 NvBufferParamsEx params = { 0, };
2125 GstGLUploadReturn ret = GST_GL_UPLOAD_ERROR;
2127 if (!gst_buffer_map (buffer, &in_map_info, GST_MAP_READ)) {
2128 GST_DEBUG_OBJECT (nvmm->upload, "Failed to map readonly NvBuffer");
2132 if (ExtractFdFromNvBuffer (in_map_info.data, &in_dmabuf_fd)) {
2133 GST_DEBUG_OBJECT (nvmm->upload, "Failed to extract fd from NvBuffer");
2136 if (NvBufferGetParamsEx (in_dmabuf_fd, ¶ms)) {
2137 GST_WARNING_OBJECT (nvmm->upload, "Failed to get NvBuffer params");
2140 dump_nv_buf_params ((GstObject *) nvmm->upload, ¶ms);
2143 gst_gl_display_egl_from_gl_display (nvmm->upload->context->display);
2145 GST_WARNING ("Failed to retrieve GstGLDisplayEGL from GstGLDisplay");
2149 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display));
2151 image = NvEGLImageFromFd (display, in_dmabuf_fd);
2153 GST_DEBUG_OBJECT (nvmm->upload, "Failed construct EGLImage "
2154 "from NvBuffer fd %i", in_dmabuf_fd);
2157 GST_DEBUG_OBJECT (nvmm->upload, "constructed EGLImage %p "
2158 "from NvBuffer fd %i", image, in_dmabuf_fd);
2160 eglimage = gst_egl_image_new_wrapped (nvmm->upload->context, image,
2161 GST_GL_RGBA, gst_memory_ref (in_map_info.memory),
2162 (GstEGLImageDestroyNotify) _egl_image_mem_unref);
2164 GST_WARNING_OBJECT (nvmm->upload, "Failed to wrap constructed "
2165 "EGLImage from NvBuffer");
2169 gst_buffer_unmap (buffer, &in_map_info);
2170 in_map_info = (GstMapInfo) GST_MAP_INFO_INIT;
2173 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
2174 (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
2176 /* TODO: buffer pool */
2177 *outbuf = gst_buffer_new ();
2178 if (!gst_gl_memory_setup_buffer (allocator, *outbuf, nvmm->params,
2179 NULL, (gpointer *) & eglimage, 1)) {
2180 GST_WARNING_OBJECT (nvmm->upload, "Failed to setup "
2181 "NVMM -> EGLImage buffer");
2184 gst_egl_image_unref (eglimage);
2186 gst_buffer_add_parent_buffer_meta (*outbuf, buffer);
2188 /* TODO: NvBuffer has some sync functions that may be more useful here */
2190 GstGLSyncMeta *sync_meta;
2192 sync_meta = gst_buffer_add_gl_sync_meta (nvmm->upload->context, *outbuf);
2194 gst_gl_sync_meta_set_sync_point (sync_meta, nvmm->upload->context);
2198 ret = GST_GL_UPLOAD_DONE;
2201 if (in_map_info.memory)
2202 gst_buffer_unmap (buffer, &in_map_info);
2204 gst_clear_object (&egl_display);
2205 gst_clear_object (&allocator);
2211 _nvmm_upload_free (gpointer impl)
2213 struct NVMMUpload *nvmm = impl;
2216 gst_gl_allocation_params_free ((GstGLAllocationParams *) nvmm->params);
2221 static const UploadMethod _nvmm_upload = {
2226 &_nvmm_upload_transform_caps,
2227 &_nvmm_upload_accept,
2228 &_nvmm_upload_propose_allocation,
2229 &_nvmm_upload_perform,
2233 #endif /* HAVE_NVMM */
2235 static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
2236 #if GST_GL_HAVE_DMABUF
2237 &_direct_dma_buf_upload,
2238 &_direct_dma_buf_external_upload,
2241 #if GST_GL_HAVE_VIV_DIRECTVIV
2244 #if defined(HAVE_NVMM)
2246 #endif /* HAVE_NVMM */
2247 &_upload_meta_upload,
2248 /* Raw data must always be last / least preferred */
2252 static GMutex upload_global_lock;
2255 gst_gl_upload_get_input_template_caps (void)
2257 GstCaps *ret = NULL;
2260 g_mutex_lock (&upload_global_lock);
2262 /* FIXME: cache this and invalidate on changes to upload_methods */
2263 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2265 gst_static_caps_get (upload_methods[i]->input_template_caps);
2266 ret = ret == NULL ? template : gst_caps_merge (ret, template);
2269 ret = gst_caps_simplify (ret);
2270 ret = gst_gl_overlay_compositor_add_caps (ret);
2271 g_mutex_unlock (&upload_global_lock);
2277 gst_gl_upload_class_init (GstGLUploadClass * klass)
2279 G_OBJECT_CLASS (klass)->finalize = gst_gl_upload_finalize;
2283 gst_gl_upload_init (GstGLUpload * upload)
2285 upload->priv = gst_gl_upload_get_instance_private (upload);
2289 * gst_gl_upload_new:
2290 * @context: a #GstGLContext
2292 * Returns: (transfer full): a new #GstGLUpload object
2295 gst_gl_upload_new (GstGLContext * context)
2297 GstGLUpload *upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL);
2300 gst_object_ref_sink (upload);
2303 gst_gl_upload_set_context (upload, context);
2305 upload->context = NULL;
2307 n = G_N_ELEMENTS (upload_methods);
2308 upload->priv->upload_impl = g_malloc (sizeof (gpointer) * n);
2309 for (i = 0; i < n; i++) {
2310 upload->priv->upload_impl[i] = upload_methods[i]->new (upload);
2313 GST_DEBUG_OBJECT (upload, "Created new GLUpload for context %" GST_PTR_FORMAT,
2320 gst_gl_upload_set_context (GstGLUpload * upload, GstGLContext * context)
2322 g_return_if_fail (upload != NULL);
2324 gst_object_replace ((GstObject **) & upload->context, (GstObject *) context);
2328 gst_gl_upload_finalize (GObject * object)
2330 GstGLUpload *upload;
2333 upload = GST_GL_UPLOAD (object);
2335 upload->priv->method_i = 0;
2337 if (upload->context) {
2338 gst_object_unref (upload->context);
2339 upload->context = NULL;
2342 if (upload->priv->in_caps) {
2343 gst_caps_unref (upload->priv->in_caps);
2344 upload->priv->in_caps = NULL;
2347 if (upload->priv->out_caps) {
2348 gst_caps_unref (upload->priv->out_caps);
2349 upload->priv->out_caps = NULL;
2352 n = G_N_ELEMENTS (upload_methods);
2353 for (i = 0; i < n; i++) {
2354 if (upload->priv->upload_impl[i])
2355 upload_methods[i]->free (upload->priv->upload_impl[i]);
2357 g_free (upload->priv->upload_impl);
2359 G_OBJECT_CLASS (gst_gl_upload_parent_class)->finalize (object);
2363 gst_gl_upload_transform_caps (GstGLUpload * upload, GstGLContext * context,
2364 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
2366 GstCaps *result, *tmp;
2369 if (upload->priv->method) {
2370 tmp = upload->priv->method->transform_caps (upload->priv->method_impl,
2371 context, direction, caps);
2374 /* If we're generating sink pad caps, make sure to include raw caps if needed by
2375 * the current method */
2376 if (direction == GST_PAD_SRC
2377 && (upload->priv->method->flags & METHOD_FLAG_CAN_ACCEPT_RAW)) {
2378 GstCapsFeatures *passthrough =
2379 gst_caps_features_from_string
2380 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
2381 GstCaps *raw_tmp = _set_caps_features_with_passthrough (tmp,
2382 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
2383 gst_caps_append (tmp, raw_tmp);
2384 gst_caps_features_free (passthrough);
2389 gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
2390 gst_caps_unref (tmp);
2394 if (!gst_caps_is_empty (result))
2397 gst_caps_unref (result);
2401 tmp = gst_caps_new_empty ();
2403 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2407 upload_methods[i]->transform_caps (upload->priv->upload_impl[i],
2408 context, direction, caps);
2411 tmp = gst_caps_merge (tmp, tmp2);
2415 result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
2416 gst_caps_unref (tmp);
2425 * gst_gl_upload_propose_allocation:
2426 * @upload: a #GstGLUpload
2427 * @decide_query: (allow-none): a #GstQuery from a decide allocation
2428 * @query: the proposed allocation query
2430 * Adds the required allocation parameters to support uploading.
2433 gst_gl_upload_propose_allocation (GstGLUpload * upload, GstQuery * decide_query,
2438 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++)
2439 upload_methods[i]->propose_allocation (upload->priv->upload_impl[i],
2440 decide_query, query);
2444 _gst_gl_upload_set_caps_unlocked (GstGLUpload * upload, GstCaps * in_caps,
2447 g_return_val_if_fail (upload != NULL, FALSE);
2448 g_return_val_if_fail (gst_caps_is_fixed (in_caps), FALSE);
2450 if (upload->priv->in_caps && upload->priv->out_caps
2451 && gst_caps_is_equal (upload->priv->in_caps, in_caps)
2452 && gst_caps_is_equal (upload->priv->out_caps, out_caps))
2455 gst_caps_replace (&upload->priv->in_caps, in_caps);
2456 gst_caps_replace (&upload->priv->out_caps, out_caps);
2458 gst_video_info_from_caps (&upload->priv->in_info, in_caps);
2459 gst_video_info_from_caps (&upload->priv->out_info, out_caps);
2461 upload->priv->method = NULL;
2462 upload->priv->method_impl = NULL;
2463 upload->priv->method_i = 0;
2469 * gst_gl_upload_set_caps:
2470 * @upload: a #GstGLUpload
2471 * @in_caps: input #GstCaps
2472 * @out_caps: output #GstCaps
2474 * Initializes @upload with the information required for upload.
2476 * Returns: whether @in_caps and @out_caps could be set on @upload
2479 gst_gl_upload_set_caps (GstGLUpload * upload, GstCaps * in_caps,
2484 GST_OBJECT_LOCK (upload);
2485 ret = _gst_gl_upload_set_caps_unlocked (upload, in_caps, out_caps);
2486 GST_OBJECT_UNLOCK (upload);
2492 * gst_gl_upload_get_caps:
2493 * @upload: a #GstGLUpload
2494 * @in_caps: (transfer full) (allow-none) (out): the input #GstCaps
2495 * @out_caps: (transfer full) (allow-none) (out): the output #GstCaps
2498 gst_gl_upload_get_caps (GstGLUpload * upload, GstCaps ** in_caps,
2499 GstCaps ** out_caps)
2501 GST_OBJECT_LOCK (upload);
2504 upload->priv->in_caps ? gst_caps_ref (upload->priv->in_caps) : NULL;
2507 upload->priv->out_caps ? gst_caps_ref (upload->priv->out_caps) : NULL;
2508 GST_OBJECT_UNLOCK (upload);
2512 _upload_find_method (GstGLUpload * upload, gpointer last_impl)
2516 /* start with the last used method after explicitly reconfiguring to
2517 * negotiate caps for this method */
2518 if (upload->priv->method_i == 0) {
2519 upload->priv->method_i = upload->priv->saved_method_i;
2520 upload->priv->saved_method_i = 0;
2523 if (upload->priv->method_i >= G_N_ELEMENTS (upload_methods)) {
2525 upload->priv->method_i = 0;
2530 method_i = upload->priv->method_i;
2532 if (last_impl == upload->priv->upload_impl[method_i])
2535 upload->priv->method = upload_methods[method_i];
2536 upload->priv->method_impl = upload->priv->upload_impl[method_i];
2538 GST_DEBUG_OBJECT (upload, "attempting upload with uploader %s",
2539 upload->priv->method->name);
2541 upload->priv->method_i++;
2547 * gst_gl_upload_perform_with_buffer:
2548 * @upload: a #GstGLUpload
2549 * @buffer: input #GstBuffer
2550 * @outbuf_ptr: (out): resulting #GstBuffer
2552 * Uploads @buffer using the transformation specified by
2553 * gst_gl_upload_set_caps() creating a new #GstBuffer in @outbuf_ptr.
2555 * Returns: whether the upload was successful
2558 gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
2559 GstBuffer ** outbuf_ptr)
2561 GstGLUploadReturn ret = GST_GL_UPLOAD_ERROR;
2562 GstBuffer *outbuf = NULL;
2563 gpointer last_impl = upload->priv->method_impl;
2564 #if !defined (GST_DISABLE_DEBUG)
2565 const UploadMethod *last_method = upload->priv->method;
2568 g_return_val_if_fail (GST_IS_GL_UPLOAD (upload), FALSE);
2569 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
2570 g_return_val_if_fail (outbuf_ptr != NULL, FALSE);
2572 GST_OBJECT_LOCK (upload);
2574 #define NEXT_METHOD \
2576 if (!_upload_find_method (upload, last_impl)) { \
2577 GST_OBJECT_UNLOCK (upload); \
2583 if (!upload->priv->method_impl)
2584 _upload_find_method (upload, last_impl);
2587 if (!upload->priv->method->accept (upload->priv->method_impl, buffer,
2588 upload->priv->in_caps, upload->priv->out_caps))
2592 upload->priv->method->perform (upload->priv->method_impl, buffer,
2594 GST_LOG_OBJECT (upload, "uploader %s returned %u, buffer: %p",
2595 upload->priv->method->name, ret, outbuf);
2596 if (ret == GST_GL_UPLOAD_UNSHARED_GL_CONTEXT) {
2599 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2600 if (upload_methods[i] == &_raw_data_upload) {
2601 upload->priv->method = &_raw_data_upload;
2602 upload->priv->method_impl = upload->priv->upload_impl[i];
2603 upload->priv->method_i = i;
2609 gst_buffer_replace (&outbuf, NULL);
2611 } else if (ret == GST_GL_UPLOAD_DONE || ret == GST_GL_UPLOAD_RECONFIGURE) {
2612 if (last_impl != upload->priv->method_impl
2613 && upload->priv->method_impl != NULL) {
2614 /* Transform the input caps using the new method. If they are compatible with the
2615 * existing upload method, we can skip reconfiguration */
2617 upload->priv->method->transform_caps (upload->priv->method_impl,
2618 upload->context, GST_PAD_SINK, upload->priv->in_caps);
2620 GST_LOG_OBJECT (upload,
2621 "Changing uploader from %s to %s with src caps %" GST_PTR_FORMAT
2622 " and old src caps %" GST_PTR_FORMAT,
2623 last_method != NULL ? last_method->name : "None",
2624 upload->priv->method->name, caps, upload->priv->out_caps);
2626 if (caps == NULL || !gst_caps_is_subset (caps, upload->priv->out_caps)) {
2627 gst_buffer_replace (&outbuf, NULL);
2628 ret = GST_GL_UPLOAD_RECONFIGURE;
2630 gst_caps_replace (&caps, NULL);
2634 upload->priv->method_impl = NULL;
2635 gst_buffer_replace (&outbuf, NULL);
2639 if (outbuf && buffer != outbuf)
2640 gst_buffer_copy_into (outbuf, buffer,
2641 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2642 *outbuf_ptr = outbuf;
2644 if (ret == GST_GL_UPLOAD_RECONFIGURE)
2645 upload->priv->saved_method_i = upload->priv->method_i - 1;
2647 GST_OBJECT_UNLOCK (upload);