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,
647 "no EGL_KHR_image_base_external extension");
651 /* This will eliminate most non-dmabuf out there */
652 if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0))) {
653 GST_DEBUG_OBJECT (dmabuf->upload, "input not dmabuf");
657 /* We cannot have multiple dmabuf per plane */
658 if (n_mem > n_planes) {
659 GST_DEBUG_OBJECT (dmabuf->upload,
660 "number of memory (%u) != number of planes (%u)", n_mem, n_planes);
664 /* Update video info based on video meta */
666 in_info->width = meta->width;
667 in_info->height = meta->height;
669 for (i = 0; i < meta->n_planes; i++) {
670 in_info->offset[i] = meta->offset[i];
671 in_info->stride[i] = meta->stride[i];
675 if (out_caps != dmabuf->out_caps) {
676 dmabuf->out_caps = out_caps;
677 if (!gst_video_info_from_caps (out_info, out_caps))
681 * When we zero-copy tiles, we need to propagate the strides, which contains
682 * the tile dimension. This is because the shader needs to know the padded
683 * size in order to correctly sample into these special buffer.
685 if (meta && GST_VIDEO_FORMAT_INFO_IS_TILED (out_info->finfo)) {
686 out_info->width = meta->width;
687 out_info->height = meta->height;
689 for (i = 0; i < meta->n_planes; i++) {
690 out_info->offset[i] = meta->offset[i];
691 out_info->stride[i] = meta->stride[i];
697 gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
698 if (!(dmabuf->params =
699 gst_gl_video_allocation_params_new_wrapped_gl_handle (dmabuf->
700 upload->context, NULL, out_info, -1, NULL, dmabuf->target, 0,
704 /* Find and validate all memories */
705 for (i = 0; i < n_planes; i++) {
711 plane_size = gst_gl_get_plane_data_size (in_info, NULL, i);
713 if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size,
714 &mem_idx, &length, &mem_skip)) {
715 GST_DEBUG_OBJECT (dmabuf->upload, "could not find memory %u", i);
719 /* We can't have more then one dmabuf per plane */
721 GST_DEBUG_OBJECT (dmabuf->upload, "data for plane %u spans %u memories",
726 mems[i] = gst_buffer_peek_memory (buffer, mem_idx);
728 /* And all memory found must be dmabuf */
729 if (!gst_is_dmabuf_memory (mems[i])) {
730 GST_DEBUG_OBJECT (dmabuf->upload, "memory %u is not dmabuf", i);
734 offset[i] = mems[i]->offset + mem_skip;
735 fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
738 if (dmabuf->direct) {
739 /* Check if this format is supported by the driver */
741 if (!gst_egl_image_check_dmabuf_direct (dmabuf->upload->context, in_info,
743 GST_DEBUG_OBJECT (dmabuf->upload, "direct check failed");
747 dmabuf->n_mem = n_planes;
749 /* Now create an EGLImage for each dmabufs */
750 for (i = 0; i < dmabuf->n_mem; i++) {
751 gint cache_id = dmabuf->direct ? 4 : i;
753 /* check if one is cached */
754 dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], cache_id);
755 if (dmabuf->eglimage[i]) {
756 dmabuf->formats[i] = dmabuf->eglimage[i]->format;
760 /* otherwise create one and cache it */
762 dmabuf->eglimage[i] =
763 gst_egl_image_from_dmabuf_direct_target (dmabuf->upload->context, fd,
764 offset, in_info, dmabuf->target);
766 dmabuf->eglimage[i] = gst_egl_image_from_dmabuf (dmabuf->upload->context,
767 fd[i], in_info, i, offset[i]);
769 if (!dmabuf->eglimage[i]) {
770 GST_DEBUG_OBJECT (dmabuf->upload, "could not create eglimage");
774 _set_cached_eglimage (mems[i], dmabuf->eglimage[i], cache_id);
775 dmabuf->formats[i] = dmabuf->eglimage[i]->format;
782 _dma_buf_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
785 /* nothing to do for now. */
789 _dma_buf_upload_perform_gl_thread (GstGLContext * context,
790 struct DmabufUpload *dmabuf)
792 GstGLMemoryAllocator *allocator;
795 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
796 (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
798 /* FIXME: buffer pool */
799 dmabuf->outbuf = gst_buffer_new ();
800 gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params,
801 dmabuf->formats, (gpointer *) dmabuf->eglimage, dmabuf->n_mem);
802 gst_object_unref (allocator);
805 static GstGLUploadReturn
806 _dma_buf_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
808 struct DmabufUpload *dmabuf = impl;
810 /* The direct path sets sinkpad caps to RGBA but this may be incorrect for
811 * the non-direct path, if that path fails to accept. In that case, we need
814 if (!dmabuf->direct &&
815 GST_VIDEO_INFO_FORMAT (&dmabuf->upload->priv->in_info) !=
816 GST_VIDEO_INFO_FORMAT (&dmabuf->out_info))
817 return GST_GL_UPLOAD_RECONFIGURE;
819 gst_gl_context_thread_add (dmabuf->upload->context,
820 (GstGLContextThreadFunc) _dma_buf_upload_perform_gl_thread, dmabuf);
823 return GST_GL_UPLOAD_ERROR;
825 gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer);
827 *outbuf = dmabuf->outbuf;
828 dmabuf->outbuf = NULL;
830 return GST_GL_UPLOAD_DONE;
834 _dma_buf_upload_free (gpointer impl)
836 struct DmabufUpload *dmabuf = impl;
839 gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
844 static const UploadMethod _dma_buf_upload = {
846 METHOD_FLAG_CAN_ACCEPT_RAW,
847 &_dma_buf_upload_caps,
848 &_dma_buf_upload_new,
849 &_dma_buf_upload_transform_caps,
850 &_dma_buf_upload_accept,
851 &_dma_buf_upload_propose_allocation,
852 &_dma_buf_upload_perform,
853 &_dma_buf_upload_free
856 /* a variant of the DMABuf uploader that relies on HW color conversion instead
860 _direct_dma_buf_upload_new (GstGLUpload * upload)
862 struct DmabufUpload *dmabuf = _dma_buf_upload_new (upload);
863 dmabuf->direct = TRUE;
864 gst_video_info_init (&dmabuf->out_info);
869 _direct_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
870 GstPadDirection direction, GstCaps * caps)
872 struct DmabufUpload *dmabuf = impl;
873 GstCapsFeatures *passthrough;
877 const GstGLFuncs *gl = context->gl_vtable;
879 if (!gl->EGLImageTargetTexture2D)
882 /* Don't propose direct DMABuf caps feature unless it can be supported */
883 if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
886 if (dmabuf->target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES &&
887 !gst_gl_context_check_feature (context, "GL_OES_EGL_image_external"))
891 passthrough = gst_caps_features_from_string
892 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
894 if (direction == GST_PAD_SINK) {
897 GstGLTextureTarget target_mask;
900 _set_caps_features_with_passthrough (caps,
901 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
903 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
905 n = gst_caps_get_size (ret);
906 for (i = 0; i < n; i++) {
907 GstStructure *s = gst_caps_get_structure (ret, i);
909 gst_structure_remove_fields (s, "chroma-site", NULL);
910 gst_structure_remove_fields (s, "colorimetry", NULL);
913 target_mask = 1 << dmabuf->target;
914 tmp = _caps_intersect_texture_target (ret, target_mask);
915 gst_caps_unref (ret);
920 GValue formats = G_VALUE_INIT;
921 gchar *format_str = g_strdup (GST_GL_MEMORY_VIDEO_FORMATS_STR);
924 _set_caps_features_with_passthrough (caps,
925 GST_CAPS_FEATURE_MEMORY_DMABUF, passthrough);
927 g_value_init (&formats, GST_TYPE_LIST);
928 gst_value_deserialize (&formats, format_str);
929 tmp = gst_caps_copy (ret);
930 gst_caps_set_value (tmp, "format", &formats);
931 gst_caps_append (ret, tmp);
933 g_value_unset (&formats);
935 n = gst_caps_get_size (ret);
936 for (i = 0; i < n; i++) {
937 GstStructure *s = gst_caps_get_structure (ret, i);
939 gst_structure_remove_fields (s, "texture-target", NULL);
943 gst_caps_features_free (passthrough);
945 GST_DEBUG_OBJECT (dmabuf->upload, "transformed %" GST_PTR_FORMAT " into %"
946 GST_PTR_FORMAT, caps, ret);
951 static const UploadMethod _direct_dma_buf_upload = {
953 METHOD_FLAG_CAN_ACCEPT_RAW,
954 &_dma_buf_upload_caps,
955 &_direct_dma_buf_upload_new,
956 &_direct_dma_buf_upload_transform_caps,
957 &_dma_buf_upload_accept,
958 &_dma_buf_upload_propose_allocation,
959 &_dma_buf_upload_perform,
960 &_dma_buf_upload_free
963 /* a variant of the direct DMABuf uploader that uses external OES textures */
966 _direct_dma_buf_external_upload_new (GstGLUpload * upload)
968 struct DmabufUpload *dmabuf = _direct_dma_buf_upload_new (upload);
969 dmabuf->target = GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
973 static const UploadMethod _direct_dma_buf_external_upload = {
974 "DirectDmabufExternal",
975 METHOD_FLAG_CAN_ACCEPT_RAW,
976 &_dma_buf_upload_caps,
977 &_direct_dma_buf_external_upload_new,
978 &_direct_dma_buf_upload_transform_caps,
979 &_dma_buf_upload_accept,
980 &_dma_buf_upload_propose_allocation,
981 &_dma_buf_upload_perform,
982 &_dma_buf_upload_free
985 #endif /* GST_GL_HAVE_DMABUF */
992 GstVideoGLTextureUploadMeta *meta;
993 guint texture_ids[GST_GL_UPLOAD_MAX_PLANES];
998 _upload_meta_upload_new (GstGLUpload * upload)
1000 struct GLUploadMeta *meta = g_new0 (struct GLUploadMeta, 1);
1002 meta->upload = upload;
1009 _upload_meta_upload_transform_caps (gpointer impl, GstGLContext * context,
1010 GstPadDirection direction, GstCaps * caps)
1012 GstCapsFeatures *passthrough =
1013 gst_caps_features_from_string
1014 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1017 if (direction == GST_PAD_SINK) {
1021 _set_caps_features_with_passthrough (caps,
1022 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1024 tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
1025 gst_caps_unref (ret);
1031 _set_caps_features_with_passthrough (caps,
1032 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, passthrough);
1033 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
1035 n = gst_caps_get_size (ret);
1036 for (i = 0; i < n; i++) {
1037 GstStructure *s = gst_caps_get_structure (ret, i);
1039 gst_structure_remove_fields (s, "texture-target", NULL);
1043 gst_caps_features_free (passthrough);
1049 _upload_meta_upload_accept (gpointer impl, GstBuffer * buffer,
1050 GstCaps * in_caps, GstCaps * out_caps)
1052 struct GLUploadMeta *upload = impl;
1053 GstCapsFeatures *features;
1054 GstVideoGLTextureUploadMeta *meta;
1055 gboolean ret = TRUE;
1056 GstStructure *config;
1059 features = gst_caps_get_features (in_caps, 0);
1061 if (!gst_caps_features_contains (features,
1062 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META))
1065 features = gst_caps_get_features (out_caps, 0);
1066 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1072 if (upload->pool == NULL)
1073 upload->pool = gst_gl_buffer_pool_new (upload->upload->context);
1075 if (!gst_buffer_pool_is_active (upload->pool)) {
1076 config = gst_buffer_pool_get_config (upload->pool);
1078 size = upload->upload->priv->in_info.size;
1079 gst_buffer_pool_config_set_params (config, in_caps, size, 0, 0);
1081 if (!gst_buffer_pool_set_config (upload->pool, config)) {
1082 GST_WARNING_OBJECT (upload->upload, "failed to set bufferpool config");
1085 gst_buffer_pool_set_active (upload->pool, TRUE);
1089 if ((meta = gst_buffer_get_video_gl_texture_upload_meta (buffer)) == NULL)
1092 if (meta->texture_type[0] != GST_VIDEO_GL_TEXTURE_TYPE_RGBA) {
1093 GST_FIXME_OBJECT (upload, "only single rgba texture supported");
1097 if (meta->texture_orientation !=
1098 GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL) {
1099 GST_FIXME_OBJECT (upload, "only x-normal, y-normal textures supported");
1108 _upload_meta_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1111 struct GLUploadMeta *upload = impl;
1112 GstStructure *gl_context;
1113 gchar *platform, *gl_apis;
1117 gst_gl_api_to_string (gst_gl_context_get_gl_api (upload->upload->
1120 gst_gl_platform_to_string (gst_gl_context_get_gl_platform (upload->
1122 handle = (gpointer) gst_gl_context_get_gl_context (upload->upload->context);
1125 gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
1126 GST_TYPE_GL_CONTEXT, upload->upload->context, "gst.gl.context.handle",
1127 G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
1128 "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
1129 gst_query_add_allocation_meta (query,
1130 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
1134 gst_structure_free (gl_context);
1138 * Uploads using gst_video_gl_texture_upload_meta_upload().
1139 * i.e. consumer of GstVideoGLTextureUploadMeta
1142 _do_upload_with_meta (GstGLContext * context, struct GLUploadMeta *upload)
1144 if (!gst_video_gl_texture_upload_meta_upload (upload->meta,
1145 upload->texture_ids)) {
1146 upload->result = FALSE;
1150 upload->result = TRUE;
1153 static GstGLUploadReturn
1154 _upload_meta_upload_perform (gpointer impl, GstBuffer * buffer,
1155 GstBuffer ** outbuf)
1157 struct GLUploadMeta *upload = impl;
1159 GstVideoInfo *in_info = &upload->upload->priv->in_info;
1160 guint max_planes = GST_VIDEO_INFO_N_PLANES (in_info);
1162 /* Support stereo views for separated multiview mode */
1163 if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
1164 GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
1165 max_planes *= GST_VIDEO_INFO_VIEWS (in_info);
1167 GST_LOG_OBJECT (upload, "Attempting upload with GstVideoGLTextureUploadMeta");
1169 upload->meta = gst_buffer_get_video_gl_texture_upload_meta (buffer);
1171 if (gst_buffer_pool_acquire_buffer (upload->pool, outbuf,
1172 NULL) != GST_FLOW_OK) {
1173 GST_WARNING_OBJECT (upload, "failed to acquire buffer from bufferpool");
1174 return GST_GL_UPLOAD_ERROR;
1177 for (i = 0; i < GST_GL_UPLOAD_MAX_PLANES; i++) {
1180 if (i < max_planes) {
1181 GstMemory *mem = gst_buffer_peek_memory (*outbuf, i);
1182 tex_id = ((GstGLMemory *) mem)->tex_id;
1185 upload->texture_ids[i] = tex_id;
1188 GST_LOG ("Uploading with GLTextureUploadMeta with textures "
1189 "%i,%i,%i,%i / %i,%i,%i,%i",
1190 upload->texture_ids[0], upload->texture_ids[1],
1191 upload->texture_ids[2], upload->texture_ids[3],
1192 upload->texture_ids[4], upload->texture_ids[5],
1193 upload->texture_ids[6], upload->texture_ids[7]);
1195 gst_gl_context_thread_add (upload->upload->context,
1196 (GstGLContextThreadFunc) _do_upload_with_meta, upload);
1198 if (!upload->result)
1199 return GST_GL_UPLOAD_ERROR;
1201 return GST_GL_UPLOAD_DONE;
1205 _upload_meta_upload_free (gpointer impl)
1207 struct GLUploadMeta *upload = impl;
1209 g_return_if_fail (impl != NULL);
1212 gst_object_unref (upload->pool);
1217 static GstStaticCaps _upload_meta_upload_caps =
1218 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1219 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA"));
1221 static const UploadMethod _upload_meta_upload = {
1223 METHOD_FLAG_CAN_SHARE_CONTEXT,
1224 &_upload_meta_upload_caps,
1225 &_upload_meta_upload_new,
1226 &_upload_meta_upload_transform_caps,
1227 &_upload_meta_upload_accept,
1228 &_upload_meta_upload_propose_allocation,
1229 &_upload_meta_upload_perform,
1230 &_upload_meta_upload_free
1233 struct RawUploadFrame
1236 GstVideoFrame frame;
1241 GstGLUpload *upload;
1242 struct RawUploadFrame *in_frame;
1243 GstGLVideoAllocationParams *params;
1246 static struct RawUploadFrame *
1247 _raw_upload_frame_new (struct RawUpload *raw, GstBuffer * buffer)
1249 struct RawUploadFrame *frame;
1256 frame = g_slice_new (struct RawUploadFrame);
1257 frame->ref_count = 1;
1259 if (!gst_video_frame_map (&frame->frame, &raw->upload->priv->in_info,
1260 buffer, GST_MAP_READ)) {
1261 g_slice_free (struct RawUploadFrame, frame);
1265 raw->upload->priv->in_info = frame->frame.info;
1266 info = &raw->upload->priv->in_info;
1268 /* Recalculate the offsets (and size) */
1270 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1271 info->offset[i] = info->size;
1272 info->size += gst_gl_get_plane_data_size (info, NULL, i);
1279 _raw_upload_frame_ref (struct RawUploadFrame *frame)
1281 g_atomic_int_inc (&frame->ref_count);
1285 _raw_upload_frame_unref (struct RawUploadFrame *frame)
1287 if (g_atomic_int_dec_and_test (&frame->ref_count)) {
1288 gst_video_frame_unmap (&frame->frame);
1289 g_slice_free (struct RawUploadFrame, frame);
1294 _raw_data_upload_new (GstGLUpload * upload)
1296 struct RawUpload *raw = g_new0 (struct RawUpload, 1);
1298 raw->upload = upload;
1304 _raw_data_upload_transform_caps (gpointer impl, GstGLContext * context,
1305 GstPadDirection direction, GstCaps * caps)
1307 GstCapsFeatures *passthrough =
1308 gst_caps_features_from_string
1309 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1312 if (direction == GST_PAD_SINK) {
1313 GstGLTextureTarget target_mask = 0;
1317 _set_caps_features_with_passthrough (caps,
1318 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1320 target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D;
1321 target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE;
1322 tmp = _caps_intersect_texture_target (ret, target_mask);
1323 gst_caps_unref (ret);
1329 _set_caps_features_with_passthrough (caps,
1330 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
1332 n = gst_caps_get_size (ret);
1333 for (i = 0; i < n; i++) {
1334 GstStructure *s = gst_caps_get_structure (ret, i);
1336 gst_structure_remove_fields (s, "texture-target", NULL);
1340 gst_caps_features_free (passthrough);
1346 _raw_data_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1349 struct RawUpload *raw = impl;
1350 GstCapsFeatures *features;
1352 features = gst_caps_get_features (out_caps, 0);
1353 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1357 _raw_upload_frame_unref (raw->in_frame);
1358 raw->in_frame = _raw_upload_frame_new (raw, buffer);
1361 gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1363 gst_gl_video_allocation_params_new_wrapped_data (raw->upload->context,
1364 NULL, &raw->upload->priv->in_info, -1, NULL,
1365 GST_GL_TEXTURE_TARGET_2D, 0, NULL, raw->in_frame,
1366 (GDestroyNotify) _raw_upload_frame_unref)))
1369 return (raw->in_frame != NULL);
1373 _raw_data_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1376 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
1379 static GstGLUploadReturn
1380 _raw_data_upload_perform (gpointer impl, GstBuffer * buffer,
1381 GstBuffer ** outbuf)
1383 GstGLBaseMemoryAllocator *allocator;
1384 struct RawUpload *raw = impl;
1386 GstVideoInfo *in_info = &raw->upload->priv->in_info;
1387 guint n_mem = GST_VIDEO_INFO_N_PLANES (in_info);
1390 GST_GL_BASE_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_default
1391 (raw->upload->context));
1393 /* FIXME Use a buffer pool to cache the generated textures */
1394 *outbuf = gst_buffer_new ();
1395 raw->params->parent.context = raw->upload->context;
1396 if (gst_gl_memory_setup_buffer ((GstGLMemoryAllocator *) allocator, *outbuf,
1397 raw->params, NULL, raw->in_frame->frame.data, n_mem)) {
1399 for (i = 0; i < n_mem; i++)
1400 _raw_upload_frame_ref (raw->in_frame);
1401 gst_buffer_add_gl_sync_meta (raw->upload->context, *outbuf);
1403 GST_ERROR_OBJECT (raw->upload, "Failed to allocate wrapped texture");
1404 gst_buffer_unref (*outbuf);
1405 gst_object_unref (allocator);
1406 return GST_GL_UPLOAD_ERROR;
1408 gst_object_unref (allocator);
1409 _raw_upload_frame_unref (raw->in_frame);
1410 raw->in_frame = NULL;
1412 return GST_GL_UPLOAD_DONE;
1416 _raw_data_upload_free (gpointer impl)
1418 struct RawUpload *raw = impl;
1421 gst_gl_allocation_params_free ((GstGLAllocationParams *) raw->params);
1426 static GstStaticCaps _raw_data_upload_caps =
1427 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
1429 static const UploadMethod _raw_data_upload = {
1432 &_raw_data_upload_caps,
1433 &_raw_data_upload_new,
1434 &_raw_data_upload_transform_caps,
1435 &_raw_data_upload_accept,
1436 &_raw_data_upload_propose_allocation,
1437 &_raw_data_upload_perform,
1438 &_raw_data_upload_free
1441 #if GST_GL_HAVE_VIV_DIRECTVIV
1443 #define GL_BGRA_EXT 0x80E1
1446 #define GL_VIV_YV12 0x8FC0
1449 #define GL_VIV_NV12 0x8FC1
1452 #define GL_VIV_YUY2 0x8FC2
1455 #define GL_VIV_UYVY 0x8FC3
1458 #define GL_VIV_NV21 0x8FC4
1461 #define GL_VIV_I420 0x8FC5
1464 struct DirectVIVUpload
1466 GstGLUpload *upload;
1468 GstGLVideoAllocationParams *params;
1469 GstBuffer *inbuf, *outbuf;
1470 void (*TexDirectVIVMap) (GLenum Target, GLsizei Width, GLsizei Height,
1471 GLenum Format, GLvoid ** Logical, const GLuint * Physical);
1472 void (*TexDirectInvalidateVIV) (GLenum Target);
1473 gboolean loaded_functions;
1476 #define GST_GL_DIRECTVIV_FORMAT "{RGBA, I420, YV12, NV12, NV21, YUY2, UYVY, BGRA, RGB16}"
1478 static GstStaticCaps _directviv_upload_caps =
1479 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DIRECTVIV_FORMAT));
1482 _directviv_upload_new (GstGLUpload * upload)
1484 struct DirectVIVUpload *directviv = g_new0 (struct DirectVIVUpload, 1);
1485 directviv->upload = upload;
1486 directviv->loaded_functions = FALSE;
1492 _directviv_upload_transform_caps (gpointer impl, GstGLContext * context,
1493 GstPadDirection direction, GstCaps * caps)
1495 GstCapsFeatures *passthrough =
1496 gst_caps_features_from_string
1497 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1500 if (direction == GST_PAD_SINK) {
1504 _set_caps_features_with_passthrough (caps,
1505 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1507 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
1508 tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
1509 gst_caps_unref (ret);
1512 ret = gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1513 (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, GST_GL_DIRECTVIV_FORMAT));
1516 gst_caps_features_free (passthrough);
1522 _directviv_upload_load_functions_gl_thread (GstGLContext * context,
1523 struct DirectVIVUpload *directviv)
1525 directviv->TexDirectVIVMap =
1526 gst_gl_context_get_proc_address (context, "glTexDirectVIVMap");
1527 directviv->TexDirectInvalidateVIV =
1528 gst_gl_context_get_proc_address (context, "glTexDirectInvalidateVIV");
1532 _directviv_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1535 struct DirectVIVUpload *directviv = impl;
1536 GstCapsFeatures *features;
1540 if (!directviv->loaded_functions && (!directviv->TexDirectInvalidateVIV ||
1541 !directviv->TexDirectVIVMap)) {
1542 gst_gl_context_thread_add (directviv->upload->context,
1543 (GstGLContextThreadFunc) _directviv_upload_load_functions_gl_thread,
1545 directviv->loaded_functions = TRUE;
1547 if (!directviv->TexDirectInvalidateVIV || !directviv->TexDirectVIVMap)
1550 features = gst_caps_get_features (out_caps, 0);
1551 if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
1554 if (directviv->params)
1555 gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1556 if (!(directviv->params =
1557 gst_gl_video_allocation_params_new (directviv->upload->context, NULL,
1558 &directviv->upload->priv->out_info, -1, NULL,
1559 GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA)))
1562 /* We only support a single memory per buffer at this point */
1563 n_mem = gst_buffer_n_memory (buffer);
1565 mem = gst_buffer_peek_memory (buffer, 0);
1570 return n_mem == 1 && mem && gst_is_phys_memory (mem);
1574 _directviv_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1580 _directviv_upload_video_format_to_gl_format (GstVideoFormat format)
1583 case GST_VIDEO_FORMAT_I420:
1585 case GST_VIDEO_FORMAT_YV12:
1587 case GST_VIDEO_FORMAT_NV12:
1589 case GST_VIDEO_FORMAT_NV21:
1591 case GST_VIDEO_FORMAT_YUY2:
1593 case GST_VIDEO_FORMAT_UYVY:
1595 case GST_VIDEO_FORMAT_RGB16:
1597 case GST_VIDEO_FORMAT_RGBA:
1599 case GST_VIDEO_FORMAT_BGRA:
1601 case GST_VIDEO_FORMAT_RGBx:
1603 case GST_VIDEO_FORMAT_BGRx:
1616 } DirectVIVUnmapData;
1619 _directviv_memory_unmap (DirectVIVUnmapData * data)
1621 gst_memory_unmap (data->memory, &data->map);
1622 gst_memory_unref (data->memory);
1623 gst_buffer_unref (data->buffer);
1628 _directviv_upload_perform_gl_thread (GstGLContext * context,
1629 struct DirectVIVUpload *directviv)
1631 static GQuark directviv_unmap_quark = 0;
1632 GstGLMemoryAllocator *allocator;
1634 GstGLMemory *out_gl_mem;
1635 GstVideoInfo *in_info;
1636 DirectVIVUnmapData *unmap_data;
1637 GstVideoMeta *vmeta;
1638 gint width, height, gl_format;
1639 const GstGLFuncs *gl;
1641 if (!directviv_unmap_quark)
1642 directviv_unmap_quark = g_quark_from_static_string ("GstGLDirectVIVUnmap");
1644 gl = context->gl_vtable;
1646 g_assert (gst_buffer_n_memory (directviv->inbuf) == 1);
1647 in_info = &directviv->upload->priv->in_info;
1648 in_mem = gst_buffer_peek_memory (directviv->inbuf, 0);
1649 unmap_data = g_new0 (DirectVIVUnmapData, 1);
1650 if (!gst_memory_map (in_mem, &unmap_data->map, GST_MAP_READ)) {
1651 g_free (unmap_data);
1654 unmap_data->phys_addr = gst_phys_memory_get_phys_addr (in_mem);
1655 if (!unmap_data->phys_addr) {
1656 gst_memory_unmap (in_mem, &unmap_data->map);
1657 g_free (unmap_data);
1660 unmap_data->memory = gst_memory_ref (in_mem);
1661 unmap_data->buffer = gst_buffer_ref (directviv->inbuf);
1664 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
1665 (GST_GL_MEMORY_PBO_ALLOCATOR_NAME));
1667 /* FIXME: buffer pool */
1668 directviv->outbuf = gst_buffer_new ();
1669 gst_gl_memory_setup_buffer (allocator, directviv->outbuf, directviv->params,
1671 gst_object_unref (allocator);
1673 out_gl_mem = (GstGLMemory *) gst_buffer_peek_memory (directviv->outbuf, 0);
1675 /* Need to keep the input memory and buffer mapped and valid until
1676 * the GL memory is not used anymore */
1677 gst_mini_object_set_qdata ((GstMiniObject *) out_gl_mem,
1678 directviv_unmap_quark, unmap_data,
1679 (GDestroyNotify) _directviv_memory_unmap);
1680 gst_buffer_add_parent_buffer_meta (directviv->outbuf, directviv->inbuf);
1682 /* width/height need to compensate for stride/padding */
1683 vmeta = gst_buffer_get_video_meta (directviv->inbuf);
1685 width = vmeta->stride[0];
1686 if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1687 height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1689 height = vmeta->offset[1] / width;
1691 width = GST_VIDEO_INFO_PLANE_STRIDE (in_info, 0);
1692 if (GST_VIDEO_INFO_N_PLANES (in_info) == 1)
1693 height = gst_memory_get_sizes (in_mem, NULL, NULL) / width;
1695 height = GST_VIDEO_INFO_PLANE_OFFSET (in_info, 1) / width;
1697 width /= GST_VIDEO_INFO_COMP_PSTRIDE (in_info, 0);
1700 _directviv_upload_video_format_to_gl_format (GST_VIDEO_INFO_FORMAT
1703 gl->BindTexture (GL_TEXTURE_2D, out_gl_mem->tex_id);
1704 directviv->TexDirectVIVMap (GL_TEXTURE_2D, width, height,
1705 gl_format, (void **) &unmap_data->map.data, &unmap_data->phys_addr);
1706 directviv->TexDirectInvalidateVIV (GL_TEXTURE_2D);
1709 static GstGLUploadReturn
1710 _directviv_upload_perform (gpointer impl, GstBuffer * buffer,
1711 GstBuffer ** outbuf)
1713 struct DirectVIVUpload *directviv = impl;
1715 directviv->inbuf = buffer;
1716 directviv->outbuf = NULL;
1717 gst_gl_context_thread_add (directviv->upload->context,
1718 (GstGLContextThreadFunc) _directviv_upload_perform_gl_thread, directviv);
1719 directviv->inbuf = NULL;
1721 if (!directviv->outbuf)
1722 return GST_GL_UPLOAD_ERROR;
1724 *outbuf = directviv->outbuf;
1725 directviv->outbuf = NULL;
1727 return GST_GL_UPLOAD_DONE;
1731 _directviv_upload_free (gpointer impl)
1733 struct DirectVIVUpload *directviv = impl;
1735 if (directviv->params)
1736 gst_gl_allocation_params_free ((GstGLAllocationParams *) directviv->params);
1741 static const UploadMethod _directviv_upload = {
1744 &_directviv_upload_caps,
1745 &_directviv_upload_new,
1746 &_directviv_upload_transform_caps,
1747 &_directviv_upload_accept,
1748 &_directviv_upload_propose_allocation,
1749 &_directviv_upload_perform,
1750 &_directviv_upload_free
1753 #endif /* GST_GL_HAVE_VIV_DIRECTVIV */
1755 #if defined(HAVE_NVMM)
1756 #include "nvbuf_utils.h"
1760 GstGLUpload *upload;
1762 GstGLVideoAllocationParams *params;
1765 GstGLTextureTarget target;
1766 GstVideoInfo out_info;
1767 /* only used for pointer comparison */
1771 #define GST_CAPS_FEATURE_MEMORY_NVMM "memory:NVMM"
1773 /* FIXME: other formats? */
1774 static GstStaticCaps _nvmm_upload_caps =
1775 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
1776 (GST_CAPS_FEATURE_MEMORY_NVMM,
1780 _nvmm_upload_new (GstGLUpload * upload)
1782 struct NVMMUpload *nvmm = g_new0 (struct NVMMUpload, 1);
1783 nvmm->upload = upload;
1784 nvmm->target = GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
1789 _nvmm_upload_transform_caps (gpointer impl, GstGLContext * context,
1790 GstPadDirection direction, GstCaps * caps)
1792 struct NVMMUpload *nvmm = impl;
1793 GstCapsFeatures *passthrough;
1797 const GstGLFuncs *gl = context->gl_vtable;
1799 if (!gl->EGLImageTargetTexture2D)
1802 /* Don't propose NVMM caps feature unless it can be supported */
1803 if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
1806 if (!gst_gl_context_check_feature (context, "EGL_KHR_image_base"))
1810 passthrough = gst_caps_features_from_string
1811 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
1813 if (direction == GST_PAD_SINK) {
1817 _set_caps_features_with_passthrough (caps,
1818 GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
1821 _caps_intersect_texture_target (ret,
1822 1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES);
1823 gst_caps_unref (ret);
1829 _set_caps_features_with_passthrough (caps,
1830 GST_CAPS_FEATURE_MEMORY_NVMM, passthrough);
1832 n = gst_caps_get_size (ret);
1833 for (i = 0; i < n; i++) {
1834 GstStructure *s = gst_caps_get_structure (ret, i);
1836 gst_structure_remove_fields (s, "texture-target", NULL);
1840 gst_caps_features_free (passthrough);
1842 GST_DEBUG_OBJECT (nvmm->upload, "transformed %" GST_PTR_FORMAT " into %"
1843 GST_PTR_FORMAT, caps, ret);
1849 _nvmm_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
1852 struct NVMMUpload *nvmm = impl;
1853 GstVideoInfo *in_info = &nvmm->upload->priv->in_info;
1854 GstVideoInfo *out_info = &nvmm->out_info;
1856 GstMapInfo in_map_info = GST_MAP_INFO_INIT;
1860 n_mem = gst_buffer_n_memory (buffer);
1862 GST_DEBUG_OBJECT (nvmm->upload, "NVMM uploader only supports "
1863 "1 memory, not %u", n_mem);
1867 meta = gst_buffer_get_video_meta (buffer);
1869 if (!nvmm->upload->context->gl_vtable->EGLImageTargetTexture2D)
1872 /* NVMM upload is only supported with EGL contexts. */
1873 if (gst_gl_context_get_gl_platform (nvmm->upload->context) !=
1874 GST_GL_PLATFORM_EGL)
1877 if (!gst_gl_context_check_feature (nvmm->upload->context,
1878 "EGL_KHR_image_base"))
1881 if (!gst_buffer_map (buffer, &in_map_info, GST_MAP_READ)) {
1882 GST_DEBUG_OBJECT (nvmm->upload, "Failed to map readonly NvBuffer");
1885 if (in_map_info.size != NvBufferGetSize ()) {
1886 GST_DEBUG_OBJECT (nvmm->upload, "Memory size (%" G_GSIZE_FORMAT ") is "
1887 "not the same as what NvBuffer advertises (%u)", in_map_info.size,
1888 NvBufferGetSize ());
1889 gst_buffer_unmap (buffer, &in_map_info);
1892 gst_buffer_unmap (buffer, &in_map_info);
1894 /* Update video info based on video meta */
1896 in_info->width = meta->width;
1897 in_info->height = meta->height;
1899 for (i = 0; i < meta->n_planes; i++) {
1900 in_info->offset[i] = meta->offset[i];
1901 in_info->stride[i] = meta->stride[i];
1905 if (out_caps != nvmm->out_caps) {
1906 nvmm->out_caps = out_caps;
1907 if (!gst_video_info_from_caps (out_info, out_caps))
1912 gst_gl_allocation_params_free ((GstGLAllocationParams *) nvmm->params);
1913 if (!(nvmm->params =
1914 gst_gl_video_allocation_params_new_wrapped_gl_handle (nvmm->
1915 upload->context, NULL, out_info, -1, NULL, nvmm->target, 0, NULL,
1924 _nvmm_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
1927 /* nothing to do for now. */
1931 _egl_image_mem_unref (GstEGLImage * image, GstMemory * mem)
1933 GstGLDisplayEGL *egl_display = NULL;
1936 egl_display = gst_gl_display_egl_from_gl_display (image->context->display);
1938 GST_ERROR ("Could not retrieve GstGLDisplayEGL from GstGLDisplay");
1942 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display));
1944 if (NvDestroyEGLImage (display, image->image)) {
1945 GST_ERROR ("Failed to destroy EGLImage %p from NvBuffer", image->image);
1947 GST_DEBUG ("destroyed EGLImage %p from NvBuffer", image->image);
1950 gst_memory_unref (mem);
1951 gst_object_unref (egl_display);
1955 payload_type_to_string (NvBufferPayloadType ptype)
1958 case NvBufferPayload_SurfArray:
1960 case NvBufferPayload_MemHandle:
1968 pixel_format_to_string (NvBufferColorFormat fmt)
1971 case NvBufferColorFormat_YUV420:
1973 case NvBufferColorFormat_YVU420:
1975 case NvBufferColorFormat_YUV422:
1977 case NvBufferColorFormat_YUV420_ER:
1979 case NvBufferColorFormat_YVU420_ER:
1981 case NvBufferColorFormat_NV12:
1983 case NvBufferColorFormat_NV12_ER:
1985 case NvBufferColorFormat_NV21:
1987 case NvBufferColorFormat_NV21_ER:
1989 case NvBufferColorFormat_UYVY:
1991 case NvBufferColorFormat_UYVY_ER:
1993 case NvBufferColorFormat_VYUY:
1995 case NvBufferColorFormat_VYUY_ER:
1997 case NvBufferColorFormat_YUYV:
1999 case NvBufferColorFormat_YUYV_ER:
2001 case NvBufferColorFormat_YVYU:
2003 case NvBufferColorFormat_YVYU_ER:
2005 case NvBufferColorFormat_ABGR32:
2007 case NvBufferColorFormat_XRGB32:
2009 case NvBufferColorFormat_ARGB32:
2011 case NvBufferColorFormat_NV12_10LE:
2013 case NvBufferColorFormat_NV12_10LE_709:
2014 return "NV12_10LE_709";
2015 case NvBufferColorFormat_NV12_10LE_709_ER:
2016 return "NV12_10LE_709_ER";
2017 case NvBufferColorFormat_NV12_10LE_2020:
2019 case NvBufferColorFormat_NV21_10LE:
2021 case NvBufferColorFormat_NV12_12LE:
2023 case NvBufferColorFormat_NV12_12LE_2020:
2024 return "NV12_12LE_2020";
2025 case NvBufferColorFormat_NV21_12LE:
2027 case NvBufferColorFormat_YUV420_709:
2028 return "YUV420_709";
2029 case NvBufferColorFormat_YUV420_709_ER:
2030 return "YUV420_709_ER";
2031 case NvBufferColorFormat_NV12_709:
2033 case NvBufferColorFormat_NV12_709_ER:
2034 return "NV12_709_ER";
2035 case NvBufferColorFormat_YUV420_2020:
2036 return "YUV420_2020";
2037 case NvBufferColorFormat_NV12_2020:
2039 case NvBufferColorFormat_SignedR16G16:
2040 return "SignedR16G16";
2041 case NvBufferColorFormat_A32:
2043 case NvBufferColorFormat_YUV444:
2045 case NvBufferColorFormat_GRAY8:
2047 case NvBufferColorFormat_NV16:
2049 case NvBufferColorFormat_NV16_10LE:
2051 case NvBufferColorFormat_NV24:
2053 case NvBufferColorFormat_NV16_ER:
2055 case NvBufferColorFormat_NV24_ER:
2057 case NvBufferColorFormat_NV16_709:
2059 case NvBufferColorFormat_NV24_709:
2061 case NvBufferColorFormat_NV16_709_ER:
2062 return "NV16_709_ER";
2063 case NvBufferColorFormat_NV24_709_ER:
2064 return "NV24_709_ER";
2065 case NvBufferColorFormat_NV24_10LE_709:
2066 return "NV24_10LE_709";
2067 case NvBufferColorFormat_NV24_10LE_709_ER:
2068 return "NV24_10LE_709_ER";
2069 case NvBufferColorFormat_NV24_10LE_2020:
2070 return "NV24_10LE_2020";
2071 case NvBufferColorFormat_NV24_12LE_2020:
2072 return "NV24_12LE_2020";
2073 case NvBufferColorFormat_RGBA_10_10_10_2_709:
2074 return "RGBA_10_10_10_2_709";
2075 case NvBufferColorFormat_RGBA_10_10_10_2_2020:
2076 return "RGBA_10_10_10_2_2020";
2077 case NvBufferColorFormat_BGRA_10_10_10_2_709:
2078 return "BGRA_10_10_10_2_709";
2079 case NvBufferColorFormat_BGRA_10_10_10_2_2020:
2080 return "BGRA_10_10_10_2_2020";
2081 case NvBufferColorFormat_Invalid:
2089 dump_nv_buf_params (GstObject * debug_object, NvBufferParamsEx * params)
2091 GST_DEBUG_OBJECT (debug_object, "nvbuffer fd: %u size %i nv_buffer: %p of "
2092 "size %u, payload: (0x%x) %s, pixel format: (0x%x) %s, n_planes: %u, "
2093 "plane 0 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u } "
2094 "plane 1 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u } "
2095 "plane 2 { wxh: %ux%u, pitch: %u, offset: %u, psize: %u, layout: %u }",
2096 params->params.dmabuf_fd, params->params.memsize,
2097 params->params.nv_buffer, params->params.nv_buffer_size,
2098 params->params.payloadType,
2099 payload_type_to_string (params->params.payloadType),
2100 params->params.pixel_format,
2101 pixel_format_to_string (params->params.pixel_format),
2102 params->params.num_planes, params->params.width[0],
2103 params->params.height[0], params->params.pitch[0],
2104 params->params.offset[0], params->params.psize[0],
2105 params->params.offset[0], params->params.width[1],
2106 params->params.height[1], params->params.pitch[1],
2107 params->params.offset[1], params->params.psize[1],
2108 params->params.offset[1], params->params.width[2],
2109 params->params.height[2], params->params.pitch[2],
2110 params->params.offset[2], params->params.psize[2],
2111 params->params.offset[2]);
2114 static GstGLUploadReturn
2115 _nvmm_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
2117 struct NVMMUpload *nvmm = impl;
2118 GstGLMemoryAllocator *allocator = NULL;
2119 GstMapInfo in_map_info = GST_MAP_INFO_INIT;
2120 GstGLDisplayEGL *egl_display = NULL;
2121 GstEGLImage *eglimage = NULL;
2122 EGLDisplay display = EGL_NO_DISPLAY;
2123 EGLImageKHR image = EGL_NO_IMAGE;
2125 NvBufferParamsEx params = { 0, };
2126 GstGLUploadReturn ret = GST_GL_UPLOAD_ERROR;
2128 if (!gst_buffer_map (buffer, &in_map_info, GST_MAP_READ)) {
2129 GST_DEBUG_OBJECT (nvmm->upload, "Failed to map readonly NvBuffer");
2133 if (ExtractFdFromNvBuffer (in_map_info.data, &in_dmabuf_fd)) {
2134 GST_DEBUG_OBJECT (nvmm->upload, "Failed to extract fd from NvBuffer");
2137 if (NvBufferGetParamsEx (in_dmabuf_fd, ¶ms)) {
2138 GST_WARNING_OBJECT (nvmm->upload, "Failed to get NvBuffer params");
2141 dump_nv_buf_params ((GstObject *) nvmm->upload, ¶ms);
2144 gst_gl_display_egl_from_gl_display (nvmm->upload->context->display);
2146 GST_WARNING ("Failed to retrieve GstGLDisplayEGL from GstGLDisplay");
2150 (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display));
2152 image = NvEGLImageFromFd (display, in_dmabuf_fd);
2154 GST_DEBUG_OBJECT (nvmm->upload, "Failed construct EGLImage "
2155 "from NvBuffer fd %i", in_dmabuf_fd);
2158 GST_DEBUG_OBJECT (nvmm->upload, "constructed EGLImage %p "
2159 "from NvBuffer fd %i", image, in_dmabuf_fd);
2161 eglimage = gst_egl_image_new_wrapped (nvmm->upload->context, image,
2162 GST_GL_RGBA, gst_memory_ref (in_map_info.memory),
2163 (GstEGLImageDestroyNotify) _egl_image_mem_unref);
2165 GST_WARNING_OBJECT (nvmm->upload, "Failed to wrap constructed "
2166 "EGLImage from NvBuffer");
2170 gst_buffer_unmap (buffer, &in_map_info);
2171 in_map_info = (GstMapInfo) GST_MAP_INFO_INIT;
2174 GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
2175 (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
2177 /* TODO: buffer pool */
2178 *outbuf = gst_buffer_new ();
2179 if (!gst_gl_memory_setup_buffer (allocator, *outbuf, nvmm->params,
2180 NULL, (gpointer *) & eglimage, 1)) {
2181 GST_WARNING_OBJECT (nvmm->upload, "Failed to setup "
2182 "NVMM -> EGLImage buffer");
2185 gst_egl_image_unref (eglimage);
2187 gst_buffer_add_parent_buffer_meta (*outbuf, buffer);
2189 /* TODO: NvBuffer has some sync functions that may be more useful here */
2191 GstGLSyncMeta *sync_meta;
2193 sync_meta = gst_buffer_add_gl_sync_meta (nvmm->upload->context, *outbuf);
2195 gst_gl_sync_meta_set_sync_point (sync_meta, nvmm->upload->context);
2199 ret = GST_GL_UPLOAD_DONE;
2202 if (in_map_info.memory)
2203 gst_buffer_unmap (buffer, &in_map_info);
2205 gst_clear_object (&egl_display);
2206 gst_clear_object (&allocator);
2212 _nvmm_upload_free (gpointer impl)
2214 struct NVMMUpload *nvmm = impl;
2217 gst_gl_allocation_params_free ((GstGLAllocationParams *) nvmm->params);
2222 static const UploadMethod _nvmm_upload = {
2227 &_nvmm_upload_transform_caps,
2228 &_nvmm_upload_accept,
2229 &_nvmm_upload_propose_allocation,
2230 &_nvmm_upload_perform,
2234 #endif /* HAVE_NVMM */
2236 static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
2237 #if GST_GL_HAVE_DMABUF
2238 &_direct_dma_buf_upload,
2239 &_direct_dma_buf_external_upload,
2242 #if GST_GL_HAVE_VIV_DIRECTVIV
2245 #if defined(HAVE_NVMM)
2247 #endif /* HAVE_NVMM */
2248 &_upload_meta_upload,
2249 /* Raw data must always be last / least preferred */
2253 static GMutex upload_global_lock;
2256 gst_gl_upload_get_input_template_caps (void)
2258 GstCaps *ret = NULL;
2261 g_mutex_lock (&upload_global_lock);
2263 /* FIXME: cache this and invalidate on changes to upload_methods */
2264 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2266 gst_static_caps_get (upload_methods[i]->input_template_caps);
2267 ret = ret == NULL ? template : gst_caps_merge (ret, template);
2270 ret = gst_caps_simplify (ret);
2271 ret = gst_gl_overlay_compositor_add_caps (ret);
2272 g_mutex_unlock (&upload_global_lock);
2278 gst_gl_upload_class_init (GstGLUploadClass * klass)
2280 G_OBJECT_CLASS (klass)->finalize = gst_gl_upload_finalize;
2284 gst_gl_upload_init (GstGLUpload * upload)
2286 upload->priv = gst_gl_upload_get_instance_private (upload);
2290 * gst_gl_upload_new:
2291 * @context: a #GstGLContext
2293 * Returns: (transfer full): a new #GstGLUpload object
2296 gst_gl_upload_new (GstGLContext * context)
2298 GstGLUpload *upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL);
2301 gst_object_ref_sink (upload);
2304 gst_gl_upload_set_context (upload, context);
2306 upload->context = NULL;
2308 n = G_N_ELEMENTS (upload_methods);
2309 upload->priv->upload_impl = g_malloc (sizeof (gpointer) * n);
2310 for (i = 0; i < n; i++) {
2311 upload->priv->upload_impl[i] = upload_methods[i]->new (upload);
2314 GST_DEBUG_OBJECT (upload, "Created new GLUpload for context %" GST_PTR_FORMAT,
2321 gst_gl_upload_set_context (GstGLUpload * upload, GstGLContext * context)
2323 g_return_if_fail (upload != NULL);
2325 gst_object_replace ((GstObject **) & upload->context, (GstObject *) context);
2329 gst_gl_upload_finalize (GObject * object)
2331 GstGLUpload *upload;
2334 upload = GST_GL_UPLOAD (object);
2336 upload->priv->method_i = 0;
2338 if (upload->context) {
2339 gst_object_unref (upload->context);
2340 upload->context = NULL;
2343 if (upload->priv->in_caps) {
2344 gst_caps_unref (upload->priv->in_caps);
2345 upload->priv->in_caps = NULL;
2348 if (upload->priv->out_caps) {
2349 gst_caps_unref (upload->priv->out_caps);
2350 upload->priv->out_caps = NULL;
2353 n = G_N_ELEMENTS (upload_methods);
2354 for (i = 0; i < n; i++) {
2355 if (upload->priv->upload_impl[i])
2356 upload_methods[i]->free (upload->priv->upload_impl[i]);
2358 g_free (upload->priv->upload_impl);
2360 G_OBJECT_CLASS (gst_gl_upload_parent_class)->finalize (object);
2364 gst_gl_upload_transform_caps (GstGLUpload * upload, GstGLContext * context,
2365 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
2367 GstCaps *result, *tmp;
2370 if (upload->priv->method) {
2371 tmp = upload->priv->method->transform_caps (upload->priv->method_impl,
2372 context, direction, caps);
2375 /* If we're generating sink pad caps, make sure to include raw caps if needed by
2376 * the current method */
2377 if (direction == GST_PAD_SRC
2378 && (upload->priv->method->flags & METHOD_FLAG_CAN_ACCEPT_RAW)) {
2379 GstCapsFeatures *passthrough =
2380 gst_caps_features_from_string
2381 (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
2382 GstCaps *raw_tmp = _set_caps_features_with_passthrough (tmp,
2383 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
2384 gst_caps_append (tmp, raw_tmp);
2385 gst_caps_features_free (passthrough);
2390 gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
2391 gst_caps_unref (tmp);
2395 if (!gst_caps_is_empty (result))
2398 gst_caps_unref (result);
2402 tmp = gst_caps_new_empty ();
2404 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2408 upload_methods[i]->transform_caps (upload->priv->upload_impl[i],
2409 context, direction, caps);
2412 tmp = gst_caps_merge (tmp, tmp2);
2416 result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
2417 gst_caps_unref (tmp);
2426 * gst_gl_upload_propose_allocation:
2427 * @upload: a #GstGLUpload
2428 * @decide_query: (allow-none): a #GstQuery from a decide allocation
2429 * @query: the proposed allocation query
2431 * Adds the required allocation parameters to support uploading.
2434 gst_gl_upload_propose_allocation (GstGLUpload * upload, GstQuery * decide_query,
2439 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++)
2440 upload_methods[i]->propose_allocation (upload->priv->upload_impl[i],
2441 decide_query, query);
2445 _gst_gl_upload_set_caps_unlocked (GstGLUpload * upload, GstCaps * in_caps,
2448 g_return_val_if_fail (upload != NULL, FALSE);
2449 g_return_val_if_fail (gst_caps_is_fixed (in_caps), FALSE);
2451 if (upload->priv->in_caps && upload->priv->out_caps
2452 && gst_caps_is_equal (upload->priv->in_caps, in_caps)
2453 && gst_caps_is_equal (upload->priv->out_caps, out_caps))
2456 gst_caps_replace (&upload->priv->in_caps, in_caps);
2457 gst_caps_replace (&upload->priv->out_caps, out_caps);
2459 gst_video_info_from_caps (&upload->priv->in_info, in_caps);
2460 gst_video_info_from_caps (&upload->priv->out_info, out_caps);
2462 upload->priv->method = NULL;
2463 upload->priv->method_impl = NULL;
2464 upload->priv->method_i = 0;
2470 * gst_gl_upload_set_caps:
2471 * @upload: a #GstGLUpload
2472 * @in_caps: input #GstCaps
2473 * @out_caps: output #GstCaps
2475 * Initializes @upload with the information required for upload.
2477 * Returns: whether @in_caps and @out_caps could be set on @upload
2480 gst_gl_upload_set_caps (GstGLUpload * upload, GstCaps * in_caps,
2485 GST_OBJECT_LOCK (upload);
2486 ret = _gst_gl_upload_set_caps_unlocked (upload, in_caps, out_caps);
2487 GST_OBJECT_UNLOCK (upload);
2493 * gst_gl_upload_get_caps:
2494 * @upload: a #GstGLUpload
2495 * @in_caps: (transfer full) (allow-none) (out): the input #GstCaps
2496 * @out_caps: (transfer full) (allow-none) (out): the output #GstCaps
2499 gst_gl_upload_get_caps (GstGLUpload * upload, GstCaps ** in_caps,
2500 GstCaps ** out_caps)
2502 GST_OBJECT_LOCK (upload);
2505 upload->priv->in_caps ? gst_caps_ref (upload->priv->in_caps) : NULL;
2508 upload->priv->out_caps ? gst_caps_ref (upload->priv->out_caps) : NULL;
2509 GST_OBJECT_UNLOCK (upload);
2513 _upload_find_method (GstGLUpload * upload, gpointer last_impl)
2517 /* start with the last used method after explicitly reconfiguring to
2518 * negotiate caps for this method */
2519 if (upload->priv->method_i == 0) {
2520 upload->priv->method_i = upload->priv->saved_method_i;
2521 upload->priv->saved_method_i = 0;
2524 if (upload->priv->method_i >= G_N_ELEMENTS (upload_methods)) {
2526 upload->priv->method_i = 0;
2531 method_i = upload->priv->method_i;
2533 if (last_impl == upload->priv->upload_impl[method_i])
2536 upload->priv->method = upload_methods[method_i];
2537 upload->priv->method_impl = upload->priv->upload_impl[method_i];
2539 GST_DEBUG_OBJECT (upload, "attempting upload with uploader %s",
2540 upload->priv->method->name);
2542 upload->priv->method_i++;
2548 * gst_gl_upload_perform_with_buffer:
2549 * @upload: a #GstGLUpload
2550 * @buffer: input #GstBuffer
2551 * @outbuf_ptr: (out): resulting #GstBuffer
2553 * Uploads @buffer using the transformation specified by
2554 * gst_gl_upload_set_caps() creating a new #GstBuffer in @outbuf_ptr.
2556 * Returns: whether the upload was successful
2559 gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
2560 GstBuffer ** outbuf_ptr)
2562 GstGLUploadReturn ret = GST_GL_UPLOAD_ERROR;
2563 GstBuffer *outbuf = NULL;
2564 gpointer last_impl = upload->priv->method_impl;
2565 #if !defined (GST_DISABLE_DEBUG)
2566 const UploadMethod *last_method = upload->priv->method;
2569 g_return_val_if_fail (GST_IS_GL_UPLOAD (upload), FALSE);
2570 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
2571 g_return_val_if_fail (outbuf_ptr != NULL, FALSE);
2573 GST_OBJECT_LOCK (upload);
2575 #define NEXT_METHOD \
2577 if (!_upload_find_method (upload, last_impl)) { \
2578 GST_OBJECT_UNLOCK (upload); \
2584 if (!upload->priv->method_impl)
2585 _upload_find_method (upload, last_impl);
2588 if (!upload->priv->method->accept (upload->priv->method_impl, buffer,
2589 upload->priv->in_caps, upload->priv->out_caps))
2593 upload->priv->method->perform (upload->priv->method_impl, buffer,
2595 GST_LOG_OBJECT (upload, "uploader %s returned %u, buffer: %p",
2596 upload->priv->method->name, ret, outbuf);
2597 if (ret == GST_GL_UPLOAD_UNSHARED_GL_CONTEXT) {
2600 for (i = 0; i < G_N_ELEMENTS (upload_methods); i++) {
2601 if (upload_methods[i] == &_raw_data_upload) {
2602 upload->priv->method = &_raw_data_upload;
2603 upload->priv->method_impl = upload->priv->upload_impl[i];
2604 upload->priv->method_i = i;
2610 gst_buffer_replace (&outbuf, NULL);
2612 } else if (ret == GST_GL_UPLOAD_DONE || ret == GST_GL_UPLOAD_RECONFIGURE) {
2613 if (last_impl != upload->priv->method_impl
2614 && upload->priv->method_impl != NULL) {
2615 /* Transform the input caps using the new method. If they are compatible with the
2616 * existing upload method, we can skip reconfiguration */
2618 upload->priv->method->transform_caps (upload->priv->method_impl,
2619 upload->context, GST_PAD_SINK, upload->priv->in_caps);
2621 GST_LOG_OBJECT (upload,
2622 "Changing uploader from %s to %s with src caps %" GST_PTR_FORMAT
2623 " and old src caps %" GST_PTR_FORMAT,
2624 last_method != NULL ? last_method->name : "None",
2625 upload->priv->method->name, caps, upload->priv->out_caps);
2627 if (caps == NULL || !gst_caps_is_subset (caps, upload->priv->out_caps)) {
2628 gst_buffer_replace (&outbuf, NULL);
2629 ret = GST_GL_UPLOAD_RECONFIGURE;
2631 gst_caps_replace (&caps, NULL);
2635 upload->priv->method_impl = NULL;
2636 gst_buffer_replace (&outbuf, NULL);
2640 if (outbuf && buffer != outbuf)
2641 gst_buffer_copy_into (outbuf, buffer,
2642 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2643 *outbuf_ptr = outbuf;
2645 if (ret == GST_GL_UPLOAD_RECONFIGURE)
2646 upload->priv->saved_method_i = upload->priv->method_i - 1;
2648 GST_OBJECT_UNLOCK (upload);