2 * Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "gstcudautils.h"
25 #include "gstcudacontext.h"
26 #include "gstcuda-private.h"
28 #ifdef HAVE_NVCODEC_GST_GL
29 #include <gst/gl/gl.h>
30 #include <gst/gl/gstglfuncs.h>
33 #ifdef GST_CUDA_HAS_D3D
34 #include <gst/d3d11/gstd3d11.h>
37 #ifdef HAVE_NVCODEC_NVMM
38 #include "gstcudanvmm.h"
41 #include "gstcudamemory.h"
43 GST_DEBUG_CATEGORY_STATIC (gst_cuda_utils_debug);
44 #define GST_CAT_DEFAULT gst_cuda_utils_debug
45 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
50 static gsize once_init = 0;
52 if (g_once_init_enter (&once_init)) {
54 GST_DEBUG_CATEGORY_INIT (gst_cuda_utils_debug, "cudautils", 0,
56 GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
57 g_once_init_leave (&once_init, 1);
62 pad_query (const GValue * item, GValue * value, gpointer user_data)
64 GstPad *pad = g_value_get_object (item);
65 GstQuery *query = user_data;
68 res = gst_pad_peer_query (pad, query);
71 g_value_set_boolean (value, TRUE);
75 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
80 run_query (GstElement * element, GstQuery * query, GstPadDirection direction)
83 GstIteratorFoldFunction func = pad_query;
86 g_value_init (&res, G_TYPE_BOOLEAN);
87 g_value_set_boolean (&res, FALSE);
90 if (direction == GST_PAD_SRC)
91 it = gst_element_iterate_src_pads (element);
93 it = gst_element_iterate_sink_pads (element);
95 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
96 gst_iterator_resync (it);
98 gst_iterator_free (it);
100 return g_value_get_boolean (&res);
104 find_cuda_context (GstElement * element, GstCudaContext ** cuda_ctx)
109 /* 1) Query downstream with GST_QUERY_CONTEXT for the context and
110 * check if upstream already has a context of the specific type
111 * 2) Query upstream as above.
113 query = gst_query_new_context (GST_CUDA_CONTEXT_TYPE);
114 if (run_query (element, query, GST_PAD_SRC)) {
115 gst_query_parse_context (query, &ctxt);
117 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
118 "found context (%p) in downstream query", ctxt);
119 gst_element_set_context (element, ctxt);
123 /* although we found cuda context above, the element does not want
124 * to use the context. Then try to find from the other direction */
125 if (*cuda_ctx == NULL && run_query (element, query, GST_PAD_SINK)) {
126 gst_query_parse_context (query, &ctxt);
128 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
129 "found context (%p) in upstream query", ctxt);
130 gst_element_set_context (element, ctxt);
134 if (*cuda_ctx == NULL) {
135 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
136 * the required context type and afterwards check if a
137 * usable context was set now. The message could
138 * be handled by the parent bins of the element and the
143 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
144 "posting need context message");
145 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
146 GST_CUDA_CONTEXT_TYPE);
147 gst_element_post_message (element, msg);
151 * Whomever responds to the need-context message performs a
152 * GstElement::set_context() with the required context in which the element
153 * is required to update the cuda_ctx or call gst_cuda_handle_set_context().
156 gst_query_unref (query);
160 context_set_cuda_context (GstContext * context, GstCudaContext * cuda_ctx)
165 g_return_if_fail (context != NULL);
167 g_object_get (G_OBJECT (cuda_ctx), "cuda-device-id", &device_id, NULL);
169 GST_CAT_LOG (GST_CAT_CONTEXT,
170 "setting GstCudaContext(%" GST_PTR_FORMAT
171 ") with cuda-device-id %d on context(%" GST_PTR_FORMAT ")",
172 cuda_ctx, device_id, context);
174 s = gst_context_writable_structure (context);
175 gst_structure_set (s, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
176 cuda_ctx, "cuda-device-id", G_TYPE_UINT, device_id, NULL);
180 * gst_cuda_ensure_element_context:
181 * @element: the #GstElement running the query
182 * @device_id: preferred device-id, pass device_id >=0 when
183 * the device_id explicitly required. Otherwise, set -1.
184 * @cuda_ctx: (inout): the resulting #GstCudaContext
186 * Perform the steps necessary for retrieving a #GstCudaContext from the
187 * surrounding elements or from the application using the #GstContext mechanism.
189 * If the content of @cuda_ctx is not %NULL, then no #GstContext query is
190 * necessary for #GstCudaContext.
192 * Returns: whether a #GstCudaContext exists in @cuda_ctx
197 gst_cuda_ensure_element_context (GstElement * element, gint device_id,
198 GstCudaContext ** cuda_ctx)
200 guint target_device_id = 0;
202 static GRecMutex lock;
203 static gsize init_lock_once = 0;
205 g_return_val_if_fail (element != NULL, FALSE);
206 g_return_val_if_fail (cuda_ctx != NULL, FALSE);
209 if (g_once_init_enter (&init_lock_once)) {
210 g_rec_mutex_init (&lock);
211 g_once_init_leave (&init_lock_once, 1);
214 g_rec_mutex_lock (&lock);
219 find_cuda_context (element, cuda_ctx);
224 target_device_id = device_id;
226 /* No available CUDA context in pipeline, create new one here */
227 *cuda_ctx = gst_cuda_context_new (target_device_id);
229 if (*cuda_ctx == NULL) {
230 GST_CAT_ERROR_OBJECT (GST_CAT_CONTEXT, element,
231 "Failed to create CUDA context with device-id %d", device_id);
237 /* Propagate new CUDA context */
239 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
240 context_set_cuda_context (context, *cuda_ctx);
242 gst_element_set_context (element, context);
244 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
245 "posting have context (%p) message with CUDA context (%p)",
247 msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
248 gst_element_post_message (GST_ELEMENT_CAST (element), msg);
252 g_rec_mutex_unlock (&lock);
258 * gst_cuda_handle_set_context:
259 * @element: a #GstElement
260 * @context: a #GstContext
261 * @device_id: preferred device-id, pass device_id >=0 when
262 * the device_id explicitly required. Otherwise, set -1.
263 * @cuda_ctx: (inout) (transfer full): location of a #GstCudaContext
265 * Helper function for implementing #GstElementClass.set_context() in
266 * CUDA capable elements.
268 * Retrieves the #GstCudaContext in @context and places the result in @cuda_ctx.
270 * Returns: whether the @cuda_ctx could be set successfully
275 gst_cuda_handle_set_context (GstElement * element,
276 GstContext * context, gint device_id, GstCudaContext ** cuda_ctx)
278 const gchar *context_type;
280 g_return_val_if_fail (element != NULL, FALSE);
281 g_return_val_if_fail (cuda_ctx != NULL, FALSE);
288 context_type = gst_context_get_context_type (context);
289 if (g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
290 const GstStructure *str;
291 GstCudaContext *other_ctx = NULL;
292 guint other_device_id = 0;
294 /* If we had context already, will not replace it */
298 str = gst_context_get_structure (context);
299 if (gst_structure_get (str, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
301 g_object_get (other_ctx, "cuda-device-id", &other_device_id, NULL);
303 if (device_id == -1 || other_device_id == device_id) {
304 GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element, "Found CUDA context");
305 *cuda_ctx = other_ctx;
310 gst_object_unref (other_ctx);
318 * gst_cuda_handle_context_query:
319 * @element: a #GstElement
320 * @query: a #GstQuery of type %GST_QUERY_CONTEXT
321 * @cuda_ctx: (transfer none) (nullable): a #GstCudaContext
323 * Returns: Whether the @query was successfully responded to from the passed
329 gst_cuda_handle_context_query (GstElement * element,
330 GstQuery * query, GstCudaContext * cuda_ctx)
332 const gchar *context_type;
333 GstContext *context, *old_context;
335 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
336 g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
337 g_return_val_if_fail (cuda_ctx == NULL
338 || GST_IS_CUDA_CONTEXT (cuda_ctx), FALSE);
342 GST_CAT_LOG_OBJECT (GST_CAT_CONTEXT, element,
343 "handle context query %" GST_PTR_FORMAT, query);
344 gst_query_parse_context_type (query, &context_type);
346 if (cuda_ctx && g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
347 gst_query_parse_context (query, &old_context);
350 context = gst_context_copy (old_context);
352 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
354 context_set_cuda_context (context, cuda_ctx);
355 gst_query_set_context (query, context);
356 gst_context_unref (context);
357 GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element,
358 "successfully set %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, cuda_ctx,
368 * gst_context_new_cuda_context:
369 * @cuda_ctx: (transfer none): a #GstCudaContext
371 * Returns: (transfer full): a new #GstContext embedding the @cuda_ctx
376 gst_context_new_cuda_context (GstCudaContext * cuda_ctx)
380 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (cuda_ctx), NULL);
384 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
385 context_set_cuda_context (context, cuda_ctx);
390 static const gchar *gst_cuda_quark_strings[] =
391 { "GstCudaQuarkGraphicsResource" };
393 static GQuark gst_cuda_quark_table[GST_CUDA_QUARK_MAX];
396 init_cuda_quark_once (void)
398 static gsize once_init = 0;
400 if (g_once_init_enter (&once_init)) {
403 for (i = 0; i < GST_CUDA_QUARK_MAX; i++)
404 gst_cuda_quark_table[i] =
405 g_quark_from_static_string (gst_cuda_quark_strings[i]);
407 g_once_init_leave (&once_init, 1);
412 * gst_cuda_quark_from_id: (skip)
413 * @id: a #GstCudaQuarkId
415 * Returns: the GQuark for given @id or 0 if @id is unknown value
420 gst_cuda_quark_from_id (GstCudaQuarkId id)
422 g_return_val_if_fail (id < GST_CUDA_QUARK_MAX, 0);
424 init_cuda_quark_once ();
427 return gst_cuda_quark_table[id];
431 * gst_cuda_graphics_resource_new: (skip)
432 * @context: (transfer none): a #GstCudaContext
433 * @graphics_context: (transfer none) (nullable): a graphics API specific context object
434 * @type: a #GstCudaGraphicsResourceType of resource registration
436 * Create new #GstCudaGraphicsResource with given @context and @type
438 * Returns: a new #GstCudaGraphicsResource.
439 * Free with gst_cuda_graphics_resource_free
443 GstCudaGraphicsResource *
444 gst_cuda_graphics_resource_new (GstCudaContext *
445 context, GstObject * graphics_context, GstCudaGraphicsResourceType type)
447 GstCudaGraphicsResource *resource;
449 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), NULL);
453 resource = g_new0 (GstCudaGraphicsResource, 1);
454 resource->cuda_context = gst_object_ref (context);
455 if (graphics_context)
456 resource->graphics_context = gst_object_ref (graphics_context);
462 * gst_cuda_graphics_resource_register_gl_buffer: (skip)
463 * @resource a #GstCudaGraphicsResource
464 * @buffer: a GL buffer object
465 * @flags: a `CUgraphicsRegisterFlags`
467 * Register the @buffer for access by CUDA.
468 * Must be called from the gl context thread with current cuda context was
469 * pushed on the current thread
471 * Returns: whether @buffer was registered or not
476 gst_cuda_graphics_resource_register_gl_buffer (GstCudaGraphicsResource *
477 resource, guint buffer, CUgraphicsRegisterFlags flags)
481 g_return_val_if_fail (resource != NULL, FALSE);
482 g_return_val_if_fail (resource->registered == FALSE, FALSE);
486 cuda_ret = CuGraphicsGLRegisterBuffer (&resource->resource, buffer, flags);
488 if (!gst_cuda_result (cuda_ret))
491 resource->registered = TRUE;
492 resource->type = GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER;
493 resource->flags = flags;
500 * gst_cuda_graphics_resource_register_d3d11_resource: (skip)
501 * @resource a #GstCudaGraphicsResource
502 * @d3d11_resource: a ID3D11Resource
503 * @flags: a CUgraphicsRegisterFlags
505 * Register the @d3d11_resource for accessing by CUDA.
506 * Must be called with d3d11 device lock with current cuda context was
507 * pushed on the current thread
509 * Returns: whether @d3d11_resource was registered or not
514 gst_cuda_graphics_resource_register_d3d11_resource (GstCudaGraphicsResource *
515 resource, ID3D11Resource * d3d11_resource, CUgraphicsRegisterFlags flags)
519 g_return_val_if_fail (resource != NULL, FALSE);
520 g_return_val_if_fail (resource->registered == FALSE, FALSE);
524 cuda_ret = CuGraphicsD3D11RegisterResource (&resource->resource,
525 d3d11_resource, flags);
527 if (!gst_cuda_result (cuda_ret))
530 resource->registered = TRUE;
531 resource->type = GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE;
532 resource->flags = flags;
539 * gst_cuda_graphics_resource_unregister: (skip)
540 * @resource: a #GstCudaGraphicsResource
542 * Unregister previously registered resource.
543 * For GL resource, this method must be called from gl context thread.
544 * Also, current cuda context should be pushed on the current thread
545 * before calling this method.
550 gst_cuda_graphics_resource_unregister (GstCudaGraphicsResource * resource)
552 g_return_if_fail (resource != NULL);
556 if (!resource->registered)
559 gst_cuda_result (CuGraphicsUnregisterResource (resource->resource));
560 resource->resource = NULL;
561 resource->registered = FALSE;
567 * gst_cuda_graphics_resource_map: (skip)
568 * @resource: a #GstCudaGraphicsResource
569 * @stream: a CUstream
570 * @flags: a CUgraphicsMapResourceFlags
572 * Map previously registered resource with map flags
574 * Returns: (nullable): the `CUgraphicsResource` if successful or %NULL when failed
579 gst_cuda_graphics_resource_map (GstCudaGraphicsResource * resource,
580 CUstream stream, CUgraphicsMapResourceFlags flags)
584 g_return_val_if_fail (resource != NULL, NULL);
585 g_return_val_if_fail (resource->registered != FALSE, NULL);
589 cuda_ret = CuGraphicsResourceSetMapFlags (resource->resource, flags);
590 if (!gst_cuda_result (cuda_ret))
593 cuda_ret = CuGraphicsMapResources (1, &resource->resource, stream);
594 if (!gst_cuda_result (cuda_ret))
597 resource->mapped = TRUE;
599 return resource->resource;
603 * gst_cuda_graphics_resource_unmap: (skip)
604 * @resource: a #GstCudaGraphicsResource
605 * @stream: a `CUstream`
607 * Unmap previously mapped resource
612 gst_cuda_graphics_resource_unmap (GstCudaGraphicsResource * resource,
615 g_return_if_fail (resource != NULL);
616 g_return_if_fail (resource->registered != FALSE);
620 if (!resource->mapped)
623 gst_cuda_result (CuGraphicsUnmapResources (1, &resource->resource, stream));
625 resource->mapped = FALSE;
628 #ifdef HAVE_NVCODEC_GST_GL
630 unregister_resource_from_gl_thread (GstGLContext * gl_context,
631 GstCudaGraphicsResource * resource)
633 GstCudaContext *cuda_context = resource->cuda_context;
635 if (!gst_cuda_context_push (cuda_context)) {
636 GST_WARNING_OBJECT (cuda_context, "failed to push CUDA context");
640 gst_cuda_graphics_resource_unregister (resource);
642 if (!gst_cuda_context_pop (NULL)) {
643 GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context");
648 #ifdef GST_CUDA_HAS_D3D
650 unregister_d3d11_resource (GstCudaGraphicsResource * resource)
652 GstCudaContext *cuda_context = resource->cuda_context;
653 GstD3D11Device *device = GST_D3D11_DEVICE (resource->graphics_context);
655 if (!gst_cuda_context_push (cuda_context)) {
656 GST_WARNING_OBJECT (cuda_context, "failed to push CUDA context");
660 gst_d3d11_device_lock (device);
661 gst_cuda_graphics_resource_unregister (resource);
662 gst_d3d11_device_unlock (device);
664 if (!gst_cuda_context_pop (NULL)) {
665 GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context");
671 * gst_cuda_graphics_resource_free: (skip)
672 * @resource: a #GstCudaGraphicsResource
679 gst_cuda_graphics_resource_free (GstCudaGraphicsResource * resource)
681 g_return_if_fail (resource != NULL);
683 if (resource->registered) {
684 #ifdef HAVE_NVCODEC_GST_GL
685 if (resource->type == GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER) {
686 gst_gl_context_thread_add ((GstGLContext *) resource->graphics_context,
687 (GstGLContextThreadFunc) unregister_resource_from_gl_thread,
691 #ifdef GST_CUDA_HAS_D3D
692 if (resource->type == GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE) {
693 unregister_d3d11_resource (resource);
697 /* FIXME: currently only opengl & d3d11 */
698 g_assert_not_reached ();
702 gst_object_unref (resource->cuda_context);
703 if (resource->graphics_context)
704 gst_object_unref (resource->graphics_context);
709 gst_cuda_buffer_copy_type_to_string (GstCudaBufferCopyType type)
712 case GST_CUDA_BUFFER_COPY_SYSTEM:
714 case GST_CUDA_BUFFER_COPY_CUDA:
716 case GST_CUDA_BUFFER_COPY_GL:
718 case GST_CUDA_BUFFER_COPY_D3D11:
720 case GST_CUDA_BUFFER_COPY_NVMM:
723 g_assert_not_reached ();
731 gst_cuda_buffer_fallback_copy (GstBuffer * dst, const GstVideoInfo * dst_info,
732 GstBuffer * src, const GstVideoInfo * src_info)
734 GstVideoFrame dst_frame, src_frame;
737 if (!gst_video_frame_map (&dst_frame, dst_info, dst, GST_MAP_WRITE)) {
738 GST_ERROR ("Failed to map dst buffer");
742 if (!gst_video_frame_map (&src_frame, src_info, src, GST_MAP_READ)) {
743 gst_video_frame_unmap (&dst_frame);
744 GST_ERROR ("Failed to map src buffer");
748 /* src and dst resolutions can be different, pick min value */
749 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&dst_frame); i++) {
750 guint dst_width_in_bytes, src_width_in_bytes;
751 guint dst_height, src_height;
752 guint width_in_bytes, height;
753 guint dst_stride, src_stride;
754 guint8 *dst_data, *src_data;
756 dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
757 GST_VIDEO_FRAME_COMP_PSTRIDE (&dst_frame, i);
758 src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
759 GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
761 width_in_bytes = MIN (dst_width_in_bytes, src_width_in_bytes);
763 dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&dst_frame, i);
764 src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
766 height = MIN (dst_height, src_height);
768 dst_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&dst_frame, i);
769 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&src_frame, i);
771 dst_data = GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
772 src_data = GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
774 for (j = 0; j < height; j++) {
775 memcpy (dst_data, src_data, width_in_bytes);
776 dst_data += dst_stride;
777 src_data += src_stride;
781 gst_video_frame_unmap (&src_frame);
782 gst_video_frame_unmap (&dst_frame);
788 map_buffer_and_fill_copy2d (GstBuffer * buf, const GstVideoInfo * info,
789 GstCudaBufferCopyType copy_type, GstVideoFrame * frame,
790 GstMapInfo * map_info, gboolean is_src,
791 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES])
793 gboolean buffer_mapped = FALSE;
796 #ifdef HAVE_NVCODEC_NVMM
797 if (copy_type == GST_CUDA_BUFFER_COPY_NVMM) {
798 NvBufSurface *surface;
799 NvBufSurfaceParams *surface_params;
800 NvBufSurfacePlaneParams *plane_params;
802 if (!gst_buffer_map (buf, map_info, GST_MAP_READ)) {
803 GST_ERROR ("Failed to map input NVMM buffer");
804 memset (map_info, 0, sizeof (GstMapInfo));
808 surface = (NvBufSurface *) map_info->data;
810 GST_TRACE ("batch-size %d, num-filled %d, memType %d",
811 surface->batchSize, surface->numFilled, surface->memType);
813 surface_params = surface->surfaceList;
814 buffer_mapped = TRUE;
815 if (!surface_params) {
816 GST_ERROR ("NVMM memory doesn't hold buffer");
820 plane_params = &surface_params->planeParams;
821 if (plane_params->num_planes != GST_VIDEO_INFO_N_PLANES (info)) {
822 GST_ERROR ("num_planes mismatch, %d / %d",
823 plane_params->num_planes, GST_VIDEO_INFO_N_PLANES (info));
827 switch (surface->memType) {
828 /* TODO: NVBUF_MEM_DEFAULT on jetson is SURFACE_ARRAY */
829 case NVBUF_MEM_DEFAULT:
830 case NVBUF_MEM_CUDA_DEVICE:
832 for (i = 0; i < plane_params->num_planes; i++) {
834 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
835 copy_params[i].srcDevice = (CUdeviceptr)
836 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
837 copy_params[i].srcPitch = plane_params->pitch[i];
839 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
840 copy_params[i].dstDevice = (CUdeviceptr)
841 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
842 copy_params[i].dstPitch = plane_params->pitch[i];
847 case NVBUF_MEM_CUDA_PINNED:
849 for (i = 0; i < plane_params->num_planes; i++) {
851 copy_params[i].srcMemoryType = CU_MEMORYTYPE_HOST;
852 copy_params[i].srcHost =
853 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
854 copy_params[i].srcPitch = plane_params->pitch[i];
856 copy_params[i].dstMemoryType = CU_MEMORYTYPE_HOST;
857 copy_params[i].dstHost =
858 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
859 copy_params[i].dstPitch = plane_params->pitch[i];
864 case NVBUF_MEM_CUDA_UNIFIED:
866 for (i = 0; i < plane_params->num_planes; i++) {
868 copy_params[i].srcMemoryType = CU_MEMORYTYPE_UNIFIED;
869 copy_params[i].srcDevice = (CUdeviceptr)
870 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
871 copy_params[i].srcPitch = plane_params->pitch[i];
873 copy_params[i].dstMemoryType = CU_MEMORYTYPE_UNIFIED;
874 copy_params[i].dstDevice = (CUdeviceptr)
875 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
876 copy_params[i].dstPitch = plane_params->pitch[i];
882 GST_ERROR ("Unexpected NVMM memory type %d", surface->memType);
886 for (i = 0; i < plane_params->num_planes; i++) {
887 gsize width_in_bytes, height;
889 width_in_bytes = plane_params->width[i] * plane_params->bytesPerPix[i];
890 height = plane_params->height[i];
892 if (copy_params[i].WidthInBytes == 0 ||
893 width_in_bytes < copy_params[i].WidthInBytes) {
894 copy_params[i].WidthInBytes = width_in_bytes;
897 if (copy_params[i].Height == 0 || height < copy_params[i].Height) {
898 copy_params[i].Height = height;
904 GstMapFlags map_flags;
907 map_flags = GST_MAP_READ;
909 map_flags = GST_MAP_WRITE;
911 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA)
912 map_flags |= GST_MAP_CUDA;
914 if (!gst_video_frame_map (frame, info, buf, map_flags)) {
915 GST_ERROR ("Failed to map buffer");
919 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (frame); i++) {
920 gsize width_in_bytes, height;
923 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA) {
924 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
925 copy_params[i].srcDevice =
926 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (frame, i);
928 copy_params[i].srcMemoryType = CU_MEMORYTYPE_HOST;
929 copy_params[i].srcHost = GST_VIDEO_FRAME_PLANE_DATA (frame, i);
931 copy_params[i].srcPitch = GST_VIDEO_FRAME_PLANE_STRIDE (frame, i);
933 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA) {
934 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
935 copy_params[i].dstDevice =
936 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (frame, i);
938 copy_params[i].dstMemoryType = CU_MEMORYTYPE_HOST;
939 copy_params[i].dstHost = GST_VIDEO_FRAME_PLANE_DATA (frame, i);
941 copy_params[i].dstPitch = GST_VIDEO_FRAME_PLANE_STRIDE (frame, i);
944 width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (frame, i) *
945 GST_VIDEO_FRAME_COMP_PSTRIDE (frame, i);
946 height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
948 if (copy_params[i].WidthInBytes == 0 ||
949 width_in_bytes < copy_params[i].WidthInBytes) {
950 copy_params[i].WidthInBytes = width_in_bytes;
953 if (copy_params[i].Height == 0 || height < copy_params[i].Height) {
954 copy_params[i].Height = height;
963 gst_buffer_unmap (buf, map_info);
964 memset (map_info, 0, sizeof (GstMapInfo));
971 unmap_buffer_or_frame (GstBuffer * buf, GstVideoFrame * frame,
972 GstMapInfo * map_info)
975 gst_video_frame_unmap (frame);
978 gst_buffer_unmap (buf, map_info);
982 gst_cuda_buffer_copy_internal (GstBuffer * dst_buf,
983 GstCudaBufferCopyType dst_type, const GstVideoInfo * dst_info,
984 GstBuffer * src_buf, GstCudaBufferCopyType src_type,
985 const GstVideoInfo * src_info, GstCudaContext * context, CUstream stream)
987 GstVideoFrame dst_frame, src_frame;
988 gboolean ret = FALSE;
989 GstMapInfo dst_map, src_map;
991 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
993 memset (copy_params, 0, sizeof (copy_params));
994 memset (&dst_frame, 0, sizeof (GstVideoFrame));
995 memset (&src_frame, 0, sizeof (GstVideoFrame));
996 memset (&dst_map, 0, sizeof (GstMapInfo));
997 memset (&src_map, 0, sizeof (GstMapInfo));
999 if (!map_buffer_and_fill_copy2d (dst_buf, dst_info,
1000 dst_type, &dst_frame, &dst_map, FALSE, copy_params)) {
1001 GST_ERROR_OBJECT (context, "Failed to map output buffer");
1005 if (!map_buffer_and_fill_copy2d (src_buf, src_info,
1006 src_type, &src_frame, &src_map, TRUE, copy_params)) {
1007 GST_ERROR_OBJECT (context, "Failed to map input buffer");
1008 unmap_buffer_or_frame (dst_buf, &dst_frame, &dst_map);
1012 if (!gst_cuda_context_push (context)) {
1013 GST_ERROR_OBJECT (context, "Failed to push our context");
1017 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (dst_info); i++) {
1018 ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
1020 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
1025 gst_cuda_result (CuStreamSynchronize (stream));
1026 gst_cuda_context_pop (NULL);
1029 unmap_buffer_or_frame (dst_buf, &src_frame, &src_map);
1030 unmap_buffer_or_frame (src_buf, &dst_frame, &dst_map);
1035 #ifdef HAVE_NVCODEC_GST_GL
1037 ensure_gl_interop (void)
1039 guint device_count = 0;
1040 CUdevice device_list[1] = { 0, };
1043 cuda_ret = CuGLGetDevices (&device_count,
1044 device_list, 1, CU_GL_DEVICE_LIST_ALL);
1046 if (cuda_ret != CUDA_SUCCESS || device_count == 0)
1052 typedef struct _GLCopyData
1055 const GstVideoInfo *src_info;
1057 const GstVideoInfo *dst_info;
1059 gboolean pbo_to_cuda;
1060 GstCudaBufferCopyType copy_type;
1061 GstCudaContext *context;
1066 static GstCudaGraphicsResource *
1067 ensure_cuda_gl_graphics_resource (GstCudaContext * context, GstMemory * mem)
1070 GstCudaGraphicsResource *ret = NULL;
1072 if (!gst_is_gl_memory_pbo (mem)) {
1073 GST_WARNING_OBJECT (context, "memory is not GL PBO memory, %s",
1074 mem->allocator->mem_type);
1078 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
1079 ret = (GstCudaGraphicsResource *)
1080 gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
1083 GstGLMemoryPBO *pbo;
1087 ret = gst_cuda_graphics_resource_new (context,
1088 GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
1089 GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
1091 if (!gst_memory_map (mem, &info, (GstMapFlags) (GST_MAP_READ | GST_MAP_GL))) {
1092 GST_ERROR_OBJECT (context, "Failed to map gl memory");
1093 gst_cuda_graphics_resource_free (ret);
1097 pbo = (GstGLMemoryPBO *) mem;
1100 if (!gst_cuda_graphics_resource_register_gl_buffer (ret,
1101 buf->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
1102 GST_ERROR_OBJECT (context, "Failed to register gl buffer");
1103 gst_memory_unmap (mem, &info);
1104 gst_cuda_graphics_resource_free (ret);
1109 gst_memory_unmap (mem, &info);
1111 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, ret,
1112 (GDestroyNotify) gst_cuda_graphics_resource_free);
1119 gl_copy_thread_func (GstGLContext * gl_context, GLCopyData * data)
1121 GstCudaGraphicsResource *resources[GST_VIDEO_MAX_PLANES];
1122 guint num_resources;
1123 GstBuffer *gl_buf, *cuda_buf;
1124 GstVideoFrame cuda_frame;
1125 GstMapInfo cuda_map_info;
1126 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
1128 GstCudaContext *context = data->context;
1129 CUstream stream = data->stream;
1131 memset (copy_params, 0, sizeof (copy_params));
1132 memset (&cuda_frame, 0, sizeof (GstVideoFrame));
1133 memset (&cuda_map_info, 0, sizeof (GstMapInfo));
1137 /* Incompatible gl context */
1138 if (!ensure_gl_interop ())
1141 if (data->pbo_to_cuda) {
1142 gl_buf = data->src_buf;
1143 cuda_buf = data->dst_buf;
1145 if (!map_buffer_and_fill_copy2d (cuda_buf,
1146 data->dst_info, data->copy_type, &cuda_frame, &cuda_map_info,
1147 FALSE, copy_params)) {
1148 GST_ERROR_OBJECT (context, "Failed to map output CUDA buffer");
1152 gl_buf = data->dst_buf;
1153 cuda_buf = data->src_buf;
1155 if (!map_buffer_and_fill_copy2d (cuda_buf,
1156 data->src_info, data->copy_type, &cuda_frame, &cuda_map_info,
1157 TRUE, copy_params)) {
1158 GST_ERROR_OBJECT (context, "Failed to map input CUDA buffer");
1163 num_resources = gst_buffer_n_memory (gl_buf);
1164 g_assert (num_resources >= GST_VIDEO_INFO_N_PLANES (data->src_info));
1166 if (!gst_cuda_context_push (context)) {
1167 GST_ERROR_OBJECT (context, "Failed to push context");
1168 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1172 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->src_info); i++) {
1173 GstMemory *mem = gst_buffer_peek_memory (gl_buf, i);
1174 GstGLMemoryPBO *pbo;
1176 resources[i] = ensure_cuda_gl_graphics_resource (context, mem);
1180 pbo = (GstGLMemoryPBO *) mem;
1181 if (!data->pbo_to_cuda) {
1182 /* Need PBO -> texture */
1183 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
1186 GST_MINI_OBJECT_FLAG_SET (pbo->pbo,
1187 GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
1189 /* get the texture into the PBO */
1190 gst_gl_memory_pbo_upload_transfer (pbo);
1191 gst_gl_memory_pbo_download_transfer (pbo);
1195 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->src_info); i++) {
1196 CUgraphicsResource cuda_resource;
1197 CUdeviceptr dev_ptr;
1200 gsize width_in_bytes, height;
1202 if (data->pbo_to_cuda) {
1204 gst_cuda_graphics_resource_map (resources[i], stream,
1205 CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY);
1208 gst_cuda_graphics_resource_map (resources[i], stream,
1209 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1212 if (!cuda_resource) {
1213 GST_ERROR_OBJECT (context, "Failed to map graphics resource %d", i);
1217 if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&dev_ptr, &size,
1219 gst_cuda_graphics_resource_unmap (resources[i], stream);
1220 GST_ERROR_OBJECT (context, "Failed to get mapped pointer");
1224 if (data->pbo_to_cuda) {
1225 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
1226 copy_params[i].srcDevice = dev_ptr;
1227 copy_params[i].srcPitch = GST_VIDEO_INFO_PLANE_STRIDE (data->src_info, i);
1229 width_in_bytes = GST_VIDEO_INFO_COMP_WIDTH (data->src_info, i) *
1230 GST_VIDEO_INFO_COMP_PSTRIDE (data->src_info, i);
1231 height = GST_VIDEO_INFO_COMP_HEIGHT (data->src_info, i);
1233 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
1234 copy_params[i].dstDevice = dev_ptr;
1235 copy_params[i].dstPitch = GST_VIDEO_INFO_PLANE_STRIDE (data->dst_info, i);
1237 width_in_bytes = GST_VIDEO_INFO_COMP_WIDTH (data->dst_info, i) *
1238 GST_VIDEO_INFO_COMP_PSTRIDE (data->dst_info, i);
1239 height = GST_VIDEO_INFO_COMP_HEIGHT (data->dst_info, i);
1242 if (width_in_bytes < copy_params[i].WidthInBytes)
1243 copy_params[i].WidthInBytes = width_in_bytes;
1245 if (height < copy_params[i].Height)
1246 copy_params[i].Height = height;
1248 copy_ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
1249 gst_cuda_graphics_resource_unmap (resources[i], stream);
1252 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
1260 gst_cuda_result (CuStreamSynchronize (stream));
1261 gst_cuda_context_pop (NULL);
1262 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1266 cuda_copy_gl_interop (GstBuffer * dst_buf, const GstVideoInfo * dst_info,
1267 GstBuffer * src_buf, const GstVideoInfo * src_info,
1268 GstGLContext * gl_context, GstCudaContext * context, CUstream stream,
1269 gboolean pbo_to_cuda, GstCudaBufferCopyType copy_type)
1273 g_assert (copy_type == GST_CUDA_BUFFER_COPY_CUDA ||
1274 copy_type == GST_CUDA_BUFFER_COPY_NVMM);
1276 data.src_buf = src_buf;
1277 data.src_info = src_info;
1278 data.dst_buf = dst_buf;
1279 data.dst_info = dst_info;
1280 data.pbo_to_cuda = pbo_to_cuda;
1281 data.copy_type = copy_type;
1282 data.context = context;
1283 data.stream = stream;
1286 gst_gl_context_thread_add (gl_context,
1287 (GstGLContextThreadFunc) gl_copy_thread_func, &data);
1293 #ifdef GST_CUDA_HAS_D3D
1295 ensure_d3d11_interop (GstCudaContext * context, GstD3D11Device * device)
1297 guint device_count = 0;
1298 guint cuda_device_id;
1299 CUdevice device_list[1] = { 0, };
1302 g_object_get (context, "cuda-device-id", &cuda_device_id, NULL);
1304 cuda_ret = CuD3D11GetDevices (&device_count,
1305 device_list, 1, gst_d3d11_device_get_device_handle (device),
1306 CU_D3D11_DEVICE_LIST_ALL);
1308 if (cuda_ret != CUDA_SUCCESS || device_count == 0)
1311 if (device_list[0] != (CUdevice) cuda_device_id)
1317 static GstCudaGraphicsResource *
1318 ensure_cuda_d3d11_graphics_resource (GstCudaContext * context, GstMemory * mem)
1321 GstCudaGraphicsResource *ret = NULL;
1323 if (!gst_is_d3d11_memory (mem)) {
1324 GST_WARNING_OBJECT (context, "memory is not D3D11 memory, %s",
1325 mem->allocator->mem_type);
1329 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
1330 ret = (GstCudaGraphicsResource *)
1331 gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
1334 ret = gst_cuda_graphics_resource_new (context,
1335 GST_OBJECT (GST_D3D11_MEMORY_CAST (mem)->device),
1336 GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE);
1338 if (!gst_cuda_graphics_resource_register_d3d11_resource (ret,
1339 gst_d3d11_memory_get_resource_handle (GST_D3D11_MEMORY_CAST (mem)),
1340 CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LOAD_STORE)) {
1341 GST_ERROR_OBJECT (context, "failed to register d3d11 resource");
1342 gst_cuda_graphics_resource_free (ret);
1347 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, ret,
1348 (GDestroyNotify) gst_cuda_graphics_resource_free);
1355 cuda_copy_d3d11_interop (GstBuffer * dst_buf, const GstVideoInfo * dst_info,
1356 GstBuffer * src_buf, const GstVideoInfo * src_info, GstD3D11Device * device,
1357 GstCudaContext * context, CUstream stream, gboolean d3d11_to_cuda)
1359 GstCudaGraphicsResource *resources[GST_VIDEO_MAX_PLANES];
1360 D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
1361 guint num_resources;
1362 GstBuffer *d3d11_buf, *cuda_buf;
1363 GstVideoFrame d3d11_frame, cuda_frame;
1364 GstMapInfo cuda_map_info;
1365 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
1367 gboolean ret = FALSE;
1369 memset (copy_params, 0, sizeof (copy_params));
1370 memset (&cuda_frame, 0, sizeof (GstVideoFrame));
1371 memset (&cuda_map_info, 0, sizeof (GstMapInfo));
1373 /* Incompatible d3d11 device */
1374 if (!ensure_d3d11_interop (context, device))
1377 if (d3d11_to_cuda) {
1378 d3d11_buf = src_buf;
1380 if (!gst_video_frame_map (&d3d11_frame, src_info, d3d11_buf,
1381 GST_MAP_READ | GST_MAP_D3D11)) {
1382 GST_ERROR_OBJECT (context, "Failed to map input D3D11 buffer");
1385 if (!map_buffer_and_fill_copy2d (cuda_buf,
1386 dst_info, GST_CUDA_BUFFER_COPY_CUDA, &cuda_frame, &cuda_map_info,
1387 FALSE, copy_params)) {
1388 GST_ERROR_OBJECT (context, "Failed to map output CUDA buffer");
1389 gst_video_frame_unmap (&d3d11_frame);
1393 d3d11_buf = dst_buf;
1395 if (!gst_video_frame_map (&d3d11_frame, dst_info, d3d11_buf,
1396 GST_MAP_WRITE | GST_MAP_D3D11)) {
1397 GST_ERROR_OBJECT (context, "Failed to map output D3D11 buffer");
1400 if (!map_buffer_and_fill_copy2d (cuda_buf,
1401 src_info, GST_CUDA_BUFFER_COPY_CUDA, &cuda_frame, &cuda_map_info,
1402 TRUE, copy_params)) {
1403 GST_ERROR_OBJECT (context, "Failed to map input CUDA buffer");
1404 gst_video_frame_unmap (&d3d11_frame);
1409 num_resources = gst_buffer_n_memory (d3d11_buf);
1410 g_assert (num_resources >= GST_VIDEO_FRAME_N_PLANES (&d3d11_frame));
1412 if (!gst_cuda_context_push (context)) {
1413 GST_ERROR_OBJECT (context, "Failed to push context");
1414 gst_video_frame_unmap (&d3d11_frame);
1415 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1419 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&d3d11_frame); i++) {
1420 GstMemory *mem = gst_buffer_peek_memory (d3d11_buf, i);
1422 resources[i] = ensure_cuda_d3d11_graphics_resource (context, mem);
1424 || !gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (mem),
1429 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&d3d11_frame); i++) {
1430 CUgraphicsResource cuda_resource;
1431 CUarray d3d11_array;
1434 if (d3d11_to_cuda) {
1436 gst_cuda_graphics_resource_map (resources[i], stream,
1437 CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY);
1440 gst_cuda_graphics_resource_map (resources[i], stream,
1441 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1444 if (!cuda_resource) {
1445 GST_ERROR_OBJECT (context, "Failed to map graphics resource %d", i);
1449 if (!gst_cuda_result (CuGraphicsSubResourceGetMappedArray (&d3d11_array,
1450 cuda_resource, 0, 0))) {
1451 gst_cuda_graphics_resource_unmap (resources[i], stream);
1452 GST_ERROR_OBJECT (context, "Failed to get mapped array");
1456 if (d3d11_to_cuda) {
1457 copy_params[i].srcMemoryType = CU_MEMORYTYPE_ARRAY;
1458 copy_params[i].srcArray = d3d11_array;
1459 copy_params[i].srcPitch =
1460 desc[i].Width * GST_VIDEO_FRAME_COMP_PSTRIDE (&d3d11_frame, i);
1462 copy_params[i].dstMemoryType = CU_MEMORYTYPE_ARRAY;
1463 copy_params[i].dstArray = d3d11_array;
1464 copy_params[i].dstPitch =
1465 desc[i].Width * GST_VIDEO_FRAME_COMP_PSTRIDE (&d3d11_frame, i);
1468 copy_ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
1469 gst_cuda_graphics_resource_unmap (resources[i], stream);
1472 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
1480 gst_cuda_result (CuStreamSynchronize (stream));
1481 gst_cuda_context_pop (NULL);
1482 gst_video_frame_unmap (&d3d11_frame);
1483 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1490 gst_cuda_buffer_copy (GstBuffer * dst, GstCudaBufferCopyType dst_type,
1491 const GstVideoInfo * dst_info, GstBuffer * src,
1492 GstCudaBufferCopyType src_type, const GstVideoInfo * src_info,
1493 GstCudaContext * context, CUstream stream)
1495 gboolean use_copy_2d = FALSE;
1496 GstMemory *dst_mem, *src_mem;
1497 #ifdef GST_CUDA_HAS_D3D
1498 D3D11_TEXTURE2D_DESC desc;
1500 GstCudaContext *cuda_context;
1502 g_return_val_if_fail (GST_IS_BUFFER (dst), FALSE);
1503 g_return_val_if_fail (dst_info != NULL, FALSE);
1504 g_return_val_if_fail (GST_IS_BUFFER (src), FALSE);
1505 g_return_val_if_fail (src_info != NULL, FALSE);
1506 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), FALSE);
1510 if (dst_type == GST_CUDA_BUFFER_COPY_NVMM &&
1511 src_type == GST_CUDA_BUFFER_COPY_NVMM) {
1512 GST_ERROR_OBJECT (context, "Not supported copy NVMM -> NVMM");
1516 if (GST_VIDEO_INFO_FORMAT (dst_info) != GST_VIDEO_INFO_FORMAT (src_info)) {
1517 GST_ERROR_OBJECT (context,
1518 "Copy between different format is not supported");
1522 if (dst_type == GST_CUDA_BUFFER_COPY_CUDA ||
1523 dst_type == GST_CUDA_BUFFER_COPY_NVMM ||
1524 src_type == GST_CUDA_BUFFER_COPY_CUDA ||
1525 src_type == GST_CUDA_BUFFER_COPY_NVMM) {
1530 GST_TRACE_OBJECT (context, "Not a device memory, use system memory copy");
1531 return gst_cuda_buffer_fallback_copy (dst, dst_info, src, src_info);
1534 dst_mem = gst_buffer_peek_memory (dst, 0);
1535 src_mem = gst_buffer_peek_memory (src, 0);
1537 #ifdef HAVE_NVCODEC_GST_GL
1538 if (src_type == GST_CUDA_BUFFER_COPY_GL && gst_is_gl_memory_pbo (src_mem)) {
1539 GstGLMemory *gl_mem = (GstGLMemory *) src_mem;
1540 GstGLContext *gl_context = gl_mem->mem.context;
1541 GstCudaContext *cuda_context = context;
1543 if (dst_type == GST_CUDA_BUFFER_COPY_CUDA && gst_is_cuda_memory (dst_mem))
1544 cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1546 GST_TRACE_OBJECT (context, "GL -> %s",
1547 gst_cuda_buffer_copy_type_to_string (dst_type));
1549 return cuda_copy_gl_interop (dst, dst_info, src, src_info, gl_context,
1550 cuda_context, stream, TRUE, dst_type);
1553 if (dst_type == GST_CUDA_BUFFER_COPY_GL && gst_is_gl_memory_pbo (dst_mem)) {
1554 GstGLMemory *gl_mem = (GstGLMemory *) dst_mem;
1555 GstGLContext *gl_context = gl_mem->mem.context;
1556 GstCudaContext *cuda_context = context;
1558 if (src_type == GST_CUDA_BUFFER_COPY_CUDA && gst_is_cuda_memory (src_mem))
1559 cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1561 GST_TRACE_OBJECT (context, "%s -> GL",
1562 gst_cuda_buffer_copy_type_to_string (src_type));
1564 return cuda_copy_gl_interop (dst, dst_info, src, src_info, gl_context,
1565 cuda_context, stream, FALSE, src_type);
1569 #ifdef GST_CUDA_HAS_D3D
1570 if (src_type == GST_CUDA_BUFFER_COPY_D3D11 && gst_is_d3d11_memory (src_mem) &&
1571 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (src_mem), &desc)
1572 && desc.Usage == D3D11_USAGE_DEFAULT && gst_is_cuda_memory (dst_mem)) {
1573 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (src_mem);
1574 GstD3D11Device *device = dmem->device;
1575 GstCudaContext *cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1578 GST_TRACE_OBJECT (context, "D3D11 -> CUDA");
1580 gst_d3d11_device_lock (device);
1581 ret = cuda_copy_d3d11_interop (dst, dst_info, src, src_info, device,
1582 cuda_context, stream, TRUE);
1583 gst_d3d11_device_unlock (device);
1588 if (dst_type == GST_CUDA_BUFFER_COPY_D3D11 && gst_is_d3d11_memory (dst_mem) &&
1589 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (dst_mem), &desc)
1590 && desc.Usage == D3D11_USAGE_DEFAULT && gst_is_cuda_memory (src_mem)) {
1591 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (dst_mem);
1592 GstD3D11Device *device = dmem->device;
1593 GstCudaContext *cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1596 GST_TRACE_OBJECT (context, "CUDA -> D3D11");
1598 gst_d3d11_device_lock (device);
1599 ret = cuda_copy_d3d11_interop (dst, dst_info, src, src_info, device,
1600 cuda_context, stream, FALSE);
1601 gst_d3d11_device_unlock (device);
1607 if (gst_is_cuda_memory (dst_mem)) {
1608 cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1609 } else if (gst_is_cuda_memory (src_mem)) {
1610 cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1612 cuda_context = context;
1615 GST_TRACE_OBJECT (context, "%s -> %s",
1616 gst_cuda_buffer_copy_type_to_string (src_type),
1617 gst_cuda_buffer_copy_type_to_string (dst_type));
1619 return gst_cuda_buffer_copy_internal (dst, dst_type, dst_info,
1620 src, src_type, src_info, cuda_context, stream);