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"
27 #ifdef HAVE_NVCODEC_GST_GL
28 #include <gst/gl/gl.h>
29 #include <gst/gl/gstglfuncs.h>
32 #ifdef HAVE_NVCODEC_GST_D3D11
33 #include <gst/d3d11/gstd3d11.h>
36 #ifdef HAVE_NVCODEC_NVMM
37 #include "gstcudanvmm.h"
40 #include "gstcudamemory.h"
42 GST_DEBUG_CATEGORY_STATIC (gst_cuda_utils_debug);
43 #define GST_CAT_DEFAULT gst_cuda_utils_debug
44 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
49 static gsize once_init = 0;
51 if (g_once_init_enter (&once_init)) {
53 GST_DEBUG_CATEGORY_INIT (gst_cuda_utils_debug, "cudautils", 0,
55 GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
56 g_once_init_leave (&once_init, 1);
61 pad_query (const GValue * item, GValue * value, gpointer user_data)
63 GstPad *pad = g_value_get_object (item);
64 GstQuery *query = user_data;
67 res = gst_pad_peer_query (pad, query);
70 g_value_set_boolean (value, TRUE);
74 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
79 run_query (GstElement * element, GstQuery * query, GstPadDirection direction)
82 GstIteratorFoldFunction func = pad_query;
85 g_value_init (&res, G_TYPE_BOOLEAN);
86 g_value_set_boolean (&res, FALSE);
89 if (direction == GST_PAD_SRC)
90 it = gst_element_iterate_src_pads (element);
92 it = gst_element_iterate_sink_pads (element);
94 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
95 gst_iterator_resync (it);
97 gst_iterator_free (it);
99 return g_value_get_boolean (&res);
103 find_cuda_context (GstElement * element, GstCudaContext ** cuda_ctx)
108 /* 1) Query downstream with GST_QUERY_CONTEXT for the context and
109 * check if upstream already has a context of the specific type
110 * 2) Query upstream as above.
112 query = gst_query_new_context (GST_CUDA_CONTEXT_TYPE);
113 if (run_query (element, query, GST_PAD_SRC)) {
114 gst_query_parse_context (query, &ctxt);
116 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
117 "found context (%p) in downstream query", ctxt);
118 gst_element_set_context (element, ctxt);
122 /* although we found cuda context above, the element does not want
123 * to use the context. Then try to find from the other direction */
124 if (*cuda_ctx == NULL && run_query (element, query, GST_PAD_SINK)) {
125 gst_query_parse_context (query, &ctxt);
127 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
128 "found context (%p) in upstream query", ctxt);
129 gst_element_set_context (element, ctxt);
133 if (*cuda_ctx == NULL) {
134 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
135 * the required context type and afterwards check if a
136 * usable context was set now. The message could
137 * be handled by the parent bins of the element and the
142 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
143 "posting need context message");
144 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
145 GST_CUDA_CONTEXT_TYPE);
146 gst_element_post_message (element, msg);
150 * Whomever responds to the need-context message performs a
151 * GstElement::set_context() with the required context in which the element
152 * is required to update the cuda_ctx or call gst_cuda_handle_set_context().
155 gst_query_unref (query);
159 context_set_cuda_context (GstContext * context, GstCudaContext * cuda_ctx)
164 g_return_if_fail (context != NULL);
166 g_object_get (G_OBJECT (cuda_ctx), "cuda-device-id", &device_id, NULL);
168 GST_CAT_LOG (GST_CAT_CONTEXT,
169 "setting GstCudaContext(%" GST_PTR_FORMAT
170 ") with cuda-device-id %d on context(%" GST_PTR_FORMAT ")",
171 cuda_ctx, device_id, context);
173 s = gst_context_writable_structure (context);
174 gst_structure_set (s, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
175 cuda_ctx, "cuda-device-id", G_TYPE_INT, device_id, NULL);
179 * gst_cuda_ensure_element_context:
180 * @element: the #GstElement running the query
181 * @device_id: preferred device-id, pass device_id >=0 when
182 * the device_id explicitly required. Otherwise, set -1.
183 * @cuda_ctx: (inout): the resulting #GstCudaContext
185 * Perform the steps necessary for retrieving a #GstCudaContext from the
186 * surrounding elements or from the application using the #GstContext mechanism.
188 * If the content of @cuda_ctx is not %NULL, then no #GstContext query is
189 * necessary for #GstCudaContext.
191 * Returns: whether a #GstCudaContext exists in @cuda_ctx
194 gst_cuda_ensure_element_context (GstElement * element, gint device_id,
195 GstCudaContext ** cuda_ctx)
197 guint target_device_id = 0;
199 g_return_val_if_fail (element != NULL, FALSE);
200 g_return_val_if_fail (cuda_ctx != NULL, FALSE);
207 find_cuda_context (element, cuda_ctx);
212 target_device_id = device_id;
214 /* No available CUDA context in pipeline, create new one here */
215 *cuda_ctx = gst_cuda_context_new (target_device_id);
217 if (*cuda_ctx == NULL) {
218 GST_CAT_ERROR_OBJECT (GST_CAT_CONTEXT, element,
219 "Failed to create CUDA context with device-id %d", device_id);
225 /* Propagate new CUDA context */
227 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
228 context_set_cuda_context (context, *cuda_ctx);
230 gst_element_set_context (element, context);
232 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
233 "posting have context (%p) message with CUDA context (%p)",
235 msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
236 gst_element_post_message (GST_ELEMENT_CAST (element), msg);
243 * gst_cuda_handle_set_context:
244 * @element: a #GstElement
245 * @context: a #GstContext
246 * @device_id: preferred device-id, pass device_id >=0 when
247 * the device_id explicitly required. Otherwise, set -1.
248 * @cuda_ctx: (inout) (transfer full): location of a #GstCudaContext
250 * Helper function for implementing #GstElementClass.set_context() in
251 * CUDA capable elements.
253 * Retrieves the #GstCudaContext in @context and places the result in @cuda_ctx.
255 * Returns: whether the @cuda_ctx could be set successfully
258 gst_cuda_handle_set_context (GstElement * element,
259 GstContext * context, gint device_id, GstCudaContext ** cuda_ctx)
261 const gchar *context_type;
263 g_return_val_if_fail (element != NULL, FALSE);
264 g_return_val_if_fail (cuda_ctx != NULL, FALSE);
271 context_type = gst_context_get_context_type (context);
272 if (g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
273 const GstStructure *str;
274 GstCudaContext *other_ctx = NULL;
275 guint other_device_id = 0;
277 /* If we had context already, will not replace it */
281 str = gst_context_get_structure (context);
282 if (gst_structure_get (str, GST_CUDA_CONTEXT_TYPE, GST_TYPE_CUDA_CONTEXT,
284 g_object_get (other_ctx, "cuda-device-id", &other_device_id, NULL);
286 if (device_id == -1 || other_device_id == device_id) {
287 GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element, "Found CUDA context");
288 *cuda_ctx = other_ctx;
293 gst_object_unref (other_ctx);
301 * gst_cuda_handle_context_query:
302 * @element: a #GstElement
303 * @query: a #GstQuery of type %GST_QUERY_CONTEXT
304 * @cuda_ctx: (transfer none) (nullable): a #GstCudaContext
306 * Returns: Whether the @query was successfully responded to from the passed
310 gst_cuda_handle_context_query (GstElement * element,
311 GstQuery * query, GstCudaContext * cuda_ctx)
313 const gchar *context_type;
314 GstContext *context, *old_context;
316 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
317 g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
318 g_return_val_if_fail (cuda_ctx == NULL
319 || GST_IS_CUDA_CONTEXT (cuda_ctx), FALSE);
323 GST_CAT_LOG_OBJECT (GST_CAT_CONTEXT, element,
324 "handle context query %" GST_PTR_FORMAT, query);
325 gst_query_parse_context_type (query, &context_type);
327 if (cuda_ctx && g_strcmp0 (context_type, GST_CUDA_CONTEXT_TYPE) == 0) {
328 gst_query_parse_context (query, &old_context);
331 context = gst_context_copy (old_context);
333 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
335 context_set_cuda_context (context, cuda_ctx);
336 gst_query_set_context (query, context);
337 gst_context_unref (context);
338 GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element,
339 "successfully set %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, cuda_ctx,
349 * gst_context_new_cuda_context:
350 * @cuda_ctx: (transfer none) a #GstCudaContext
352 * Returns: (transfer full) (nullable): a new #GstContext embedding the @cuda_ctx
356 gst_context_new_cuda_context (GstCudaContext * cuda_ctx)
360 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (cuda_ctx), NULL);
362 context = gst_context_new (GST_CUDA_CONTEXT_TYPE, TRUE);
363 context_set_cuda_context (context, cuda_ctx);
368 static const gchar *gst_cuda_quark_strings[] =
369 { "GstCudaQuarkGraphicsResource" };
371 static GQuark gst_cuda_quark_table[GST_CUDA_QUARK_MAX];
374 init_cuda_quark_once (void)
376 static gsize once_init = 0;
378 if (g_once_init_enter (&once_init)) {
381 for (i = 0; i < GST_CUDA_QUARK_MAX; i++)
382 gst_cuda_quark_table[i] =
383 g_quark_from_static_string (gst_cuda_quark_strings[i]);
385 g_once_init_leave (&once_init, 1);
390 * gst_cuda_quark_from_id: (skip)
391 * @id: a #GstCudaQuarkId
393 * Returns: the GQuark for given @id or 0 if @id is unknown value
396 gst_cuda_quark_from_id (GstCudaQuarkId id)
398 g_return_val_if_fail (id < GST_CUDA_QUARK_MAX, 0);
400 init_cuda_quark_once ();
403 return gst_cuda_quark_table[id];
407 * gst_cuda_graphics_resource_new: (skip)
408 * @context: (transfer none): a #GstCudaContext
409 * @graphics_context: (transfer none) (nullable): a graphics API specific context object
410 * @type: a #GstCudaGraphicsResourceType of resource registration
412 * Create new #GstCudaGraphicsResource with given @context and @type
414 * Returns: a new #GstCudaGraphicsResource.
415 * Free with gst_cuda_graphics_resource_free
417 GstCudaGraphicsResource *
418 gst_cuda_graphics_resource_new (GstCudaContext *
419 context, GstObject * graphics_context, GstCudaGraphicsResourceType type)
421 GstCudaGraphicsResource *resource;
423 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), NULL);
427 resource = g_new0 (GstCudaGraphicsResource, 1);
428 resource->cuda_context = gst_object_ref (context);
429 if (graphics_context)
430 resource->graphics_context = gst_object_ref (graphics_context);
436 * gst_cuda_graphics_resource_register_gl_buffer: (skip)
437 * @resource a #GstCudaGraphicsResource
438 * @buffer: a GL buffer object
439 * @flags: a #CUgraphicsRegisterFlags
441 * Register the @buffer for access by CUDA.
442 * Must be called from the gl context thread with current cuda context was
443 * pushed on the current thread
445 * Returns: whether @buffer was registered or not
448 gst_cuda_graphics_resource_register_gl_buffer (GstCudaGraphicsResource *
449 resource, guint buffer, CUgraphicsRegisterFlags flags)
453 g_return_val_if_fail (resource != NULL, FALSE);
454 g_return_val_if_fail (resource->registered == FALSE, FALSE);
458 cuda_ret = CuGraphicsGLRegisterBuffer (&resource->resource, buffer, flags);
460 if (!gst_cuda_result (cuda_ret))
463 resource->registered = TRUE;
464 resource->type = GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER;
465 resource->flags = flags;
471 * gst_cuda_graphics_resource_register_d3d11_resource: (skip)
472 * @resource a #GstCudaGraphicsResource
473 * @d3d11_resource: a ID3D11Resource
474 * @flags: a #CUgraphicsRegisterFlags
476 * Register the @d3d11_resource for accessing by CUDA.
477 * Must be called with d3d11 device lock with current cuda context was
478 * pushed on the current thread
480 * Returns: whether @d3d11_resource was registered or not
483 gst_cuda_graphics_resource_register_d3d11_resource (GstCudaGraphicsResource *
484 resource, gpointer d3d11_resource, CUgraphicsRegisterFlags flags)
488 g_return_val_if_fail (resource != NULL, FALSE);
489 g_return_val_if_fail (resource->registered == FALSE, FALSE);
493 cuda_ret = CuGraphicsD3D11RegisterResource (&resource->resource,
494 d3d11_resource, flags);
496 if (!gst_cuda_result (cuda_ret))
499 resource->registered = TRUE;
500 resource->type = GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE;
501 resource->flags = flags;
507 * gst_cuda_graphics_resource_unregister: (skip)
508 * @resource: a #GstCudaGraphicsResource
510 * Unregister previously registered resource.
511 * For GL resource, this method must be called from gl context thread.
512 * Also, current cuda context should be pushed on the current thread
513 * before calling this method.
516 gst_cuda_graphics_resource_unregister (GstCudaGraphicsResource * resource)
518 g_return_if_fail (resource != NULL);
522 if (!resource->registered)
525 gst_cuda_result (CuGraphicsUnregisterResource (resource->resource));
526 resource->resource = NULL;
527 resource->registered = FALSE;
533 * gst_cuda_graphics_resource_map: (skip)
534 * @resource: a #GstCudaGraphicsResource
535 * @stream: a #CUstream
536 * @flags: a #CUgraphicsMapResourceFlags
538 * Map previously registered resource with map flags
540 * Returns: the #CUgraphicsResource if successful or %NULL when failed
543 gst_cuda_graphics_resource_map (GstCudaGraphicsResource * resource,
544 CUstream stream, CUgraphicsMapResourceFlags flags)
548 g_return_val_if_fail (resource != NULL, NULL);
549 g_return_val_if_fail (resource->registered != FALSE, NULL);
553 cuda_ret = CuGraphicsResourceSetMapFlags (resource->resource, flags);
554 if (!gst_cuda_result (cuda_ret))
557 cuda_ret = CuGraphicsMapResources (1, &resource->resource, stream);
558 if (!gst_cuda_result (cuda_ret))
561 resource->mapped = TRUE;
563 return resource->resource;
567 * gst_cuda_graphics_resource_unmap: (skip)
568 * @resource: a #GstCudaGraphicsResource
569 * @stream: a #CUstream
571 * Unmap previously mapped resource
574 gst_cuda_graphics_resource_unmap (GstCudaGraphicsResource * resource,
577 g_return_if_fail (resource != NULL);
578 g_return_if_fail (resource->registered != FALSE);
582 if (!resource->mapped)
585 gst_cuda_result (CuGraphicsUnmapResources (1, &resource->resource, stream));
587 resource->mapped = FALSE;
590 #ifdef HAVE_NVCODEC_GST_GL
592 unregister_resource_from_gl_thread (GstGLContext * gl_context,
593 GstCudaGraphicsResource * resource)
595 GstCudaContext *cuda_context = resource->cuda_context;
597 if (!gst_cuda_context_push (cuda_context)) {
598 GST_WARNING_OBJECT (cuda_context, "failed to push CUDA context");
602 gst_cuda_graphics_resource_unregister (resource);
604 if (!gst_cuda_context_pop (NULL)) {
605 GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context");
610 #ifdef HAVE_NVCODEC_GST_D3D11
612 unregister_d3d11_resource (GstCudaGraphicsResource * resource)
614 GstCudaContext *cuda_context = resource->cuda_context;
615 GstD3D11Device *device = GST_D3D11_DEVICE (resource->graphics_context);
617 if (!gst_cuda_context_push (cuda_context)) {
618 GST_WARNING_OBJECT (cuda_context, "failed to push CUDA context");
622 gst_d3d11_device_lock (device);
623 gst_cuda_graphics_resource_unregister (resource);
624 gst_d3d11_device_unlock (device);
626 if (!gst_cuda_context_pop (NULL)) {
627 GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context");
633 * gst_cuda_graphics_resource_free: (skip)
634 * @resource: a #GstCudaGraphicsResource
639 gst_cuda_graphics_resource_free (GstCudaGraphicsResource * resource)
641 g_return_if_fail (resource != NULL);
643 if (resource->registered) {
644 #ifdef HAVE_NVCODEC_GST_GL
645 if (resource->type == GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER) {
646 gst_gl_context_thread_add ((GstGLContext *) resource->graphics_context,
647 (GstGLContextThreadFunc) unregister_resource_from_gl_thread,
651 #ifdef HAVE_NVCODEC_GST_D3D11
652 if (resource->type == GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE) {
653 unregister_d3d11_resource (resource);
657 /* FIXME: currently only opengl & d3d11 */
658 g_assert_not_reached ();
662 gst_object_unref (resource->cuda_context);
663 if (resource->graphics_context)
664 gst_object_unref (resource->graphics_context);
669 gst_cuda_buffery_copy_type_to_string (GstCudaBufferCopyType type)
672 case GST_CUDA_BUFFER_COPY_SYSTEM:
674 case GST_CUDA_BUFFER_COPY_CUDA:
676 case GST_CUDA_BUFFER_COPY_GL:
678 case GST_CUDA_BUFFER_COPY_D3D11:
680 case GST_CUDA_BUFFER_COPY_NVMM:
683 g_assert_not_reached ();
691 gst_cuda_buffer_fallback_copy (GstBuffer * dst, const GstVideoInfo * dst_info,
692 GstBuffer * src, const GstVideoInfo * src_info)
694 GstVideoFrame dst_frame, src_frame;
697 if (!gst_video_frame_map (&dst_frame, dst_info, dst, GST_MAP_WRITE)) {
698 GST_ERROR ("Failed to map dst buffer");
702 if (!gst_video_frame_map (&src_frame, src_info, src, GST_MAP_READ)) {
703 gst_video_frame_unmap (&dst_frame);
704 GST_ERROR ("Failed to map src buffer");
708 /* src and dst resolutions can be different, pick min value */
709 for (i = 0; GST_VIDEO_FRAME_N_PLANES (&dst_frame); i++) {
710 guint dst_width_in_bytes, src_width_in_bytes;
711 guint dst_height, src_height;
712 guint width_in_bytes, height;
713 guint dst_stride, src_stride;
714 guint8 *dst_data, *src_data;
716 dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
717 GST_VIDEO_FRAME_COMP_PSTRIDE (&dst_frame, i);
718 src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
719 GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
721 width_in_bytes = MIN (dst_width_in_bytes, src_width_in_bytes);
723 dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&dst_frame, i);
724 src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
726 height = MIN (dst_height, src_height);
728 dst_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&dst_frame, i);
729 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&src_frame, i);
731 dst_data = GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
732 src_data = GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
734 for (j = 0; j < height; j++) {
735 memcpy (dst_data, src_data, width_in_bytes);
736 dst_data += dst_stride;
737 src_data += src_stride;
741 gst_video_frame_unmap (&src_frame);
742 gst_video_frame_unmap (&dst_frame);
748 map_buffer_and_fill_copy2d (GstBuffer * buf, const GstVideoInfo * info,
749 GstCudaBufferCopyType copy_type, GstVideoFrame * frame,
750 GstMapInfo * map_info, gboolean is_src,
751 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES])
753 gboolean buffer_mapped = FALSE;
756 #ifdef HAVE_NVCODEC_NVMM
757 if (copy_type == GST_CUDA_BUFFER_COPY_NVMM) {
758 NvBufSurface *surface;
759 NvBufSurfaceParams *surface_params;
760 NvBufSurfacePlaneParams *plane_params;
762 if (!gst_buffer_map (buf, map_info, GST_MAP_READ)) {
763 GST_ERROR ("Failed to map input NVMM buffer");
764 memset (map_info, 0, sizeof (GstMapInfo));
768 surface = (NvBufSurface *) map_info->data;
770 GST_TRACE ("batch-size %d, num-filled %d, memType %d",
771 surface->batchSize, surface->numFilled, surface->memType);
773 surface_params = surface->surfaceList;
774 buffer_mapped = TRUE;
775 if (!surface_params) {
776 GST_ERROR ("NVMM memory doesn't hold buffer");
780 plane_params = &surface_params->planeParams;
781 if (plane_params->num_planes != GST_VIDEO_INFO_N_PLANES (info)) {
782 GST_ERROR ("num_planes mismatch, %d / %d",
783 plane_params->num_planes, GST_VIDEO_INFO_N_PLANES (info));
787 switch (surface->memType) {
788 /* TODO: NVBUF_MEM_DEFAULT on jetson is SURFACE_ARRAY */
789 case NVBUF_MEM_DEFAULT:
790 case NVBUF_MEM_CUDA_DEVICE:
792 for (i = 0; i < plane_params->num_planes; i++) {
794 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
795 copy_params[i].srcDevice = (CUdeviceptr)
796 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
797 copy_params[i].srcPitch = plane_params->pitch[i];
799 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
800 copy_params[i].dstDevice = (CUdeviceptr)
801 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
802 copy_params[i].dstPitch = plane_params->pitch[i];
807 case NVBUF_MEM_CUDA_PINNED:
809 for (i = 0; i < plane_params->num_planes; i++) {
811 copy_params[i].srcMemoryType = CU_MEMORYTYPE_HOST;
812 copy_params[i].srcHost =
813 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
814 copy_params[i].srcPitch = plane_params->pitch[i];
816 copy_params[i].dstMemoryType = CU_MEMORYTYPE_HOST;
817 copy_params[i].dstHost =
818 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
819 copy_params[i].dstPitch = plane_params->pitch[i];
824 case NVBUF_MEM_CUDA_UNIFIED:
826 for (i = 0; i < plane_params->num_planes; i++) {
828 copy_params[i].srcMemoryType = CU_MEMORYTYPE_UNIFIED;
829 copy_params[i].srcDevice = (CUdeviceptr)
830 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
831 copy_params[i].srcPitch = plane_params->pitch[i];
833 copy_params[i].dstMemoryType = CU_MEMORYTYPE_UNIFIED;
834 copy_params[i].dstDevice = (CUdeviceptr)
835 ((guint8 *) surface_params->dataPtr + plane_params->offset[i]);
836 copy_params[i].dstPitch = plane_params->pitch[i];
842 GST_ERROR ("Unexpected NVMM memory type %d", surface->memType);
846 for (i = 0; i < plane_params->num_planes; i++) {
847 gsize width_in_bytes, height;
849 width_in_bytes = plane_params->width[i] * plane_params->bytesPerPix[i];
850 height = plane_params->height[i];
852 if (copy_params[i].WidthInBytes == 0 ||
853 width_in_bytes < copy_params[i].WidthInBytes) {
854 copy_params[i].WidthInBytes = width_in_bytes;
857 if (copy_params[i].Height == 0 || height < copy_params[i].Height) {
858 copy_params[i].Height = height;
864 GstMapFlags map_flags;
867 map_flags = GST_MAP_READ;
869 map_flags = GST_MAP_WRITE;
871 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA)
872 map_flags |= GST_MAP_CUDA;
874 if (!gst_video_frame_map (frame, info, buf, map_flags)) {
875 GST_ERROR ("Failed to map buffer");
879 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (frame); i++) {
880 gsize width_in_bytes, height;
883 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA) {
884 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
885 copy_params[i].srcDevice =
886 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (frame, i);
888 copy_params[i].srcMemoryType = CU_MEMORYTYPE_HOST;
889 copy_params[i].srcHost = GST_VIDEO_FRAME_PLANE_DATA (frame, i);
891 copy_params[i].srcPitch = GST_VIDEO_FRAME_PLANE_STRIDE (frame, i);
893 if (copy_type == GST_CUDA_BUFFER_COPY_CUDA) {
894 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
895 copy_params[i].dstDevice =
896 (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (frame, i);
898 copy_params[i].dstMemoryType = CU_MEMORYTYPE_HOST;
899 copy_params[i].dstHost = GST_VIDEO_FRAME_PLANE_DATA (frame, i);
901 copy_params[i].dstPitch = GST_VIDEO_FRAME_PLANE_STRIDE (frame, i);
904 width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (frame, i) *
905 GST_VIDEO_FRAME_COMP_PSTRIDE (frame, i);
906 height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
908 if (copy_params[i].WidthInBytes == 0 ||
909 width_in_bytes < copy_params[i].WidthInBytes) {
910 copy_params[i].WidthInBytes = width_in_bytes;
913 if (copy_params[i].Height == 0 || height < copy_params[i].Height) {
914 copy_params[i].Height = height;
923 gst_buffer_unmap (buf, map_info);
924 memset (map_info, 0, sizeof (GstMapInfo));
931 unmap_buffer_or_frame (GstBuffer * buf, GstVideoFrame * frame,
932 GstMapInfo * map_info)
935 gst_video_frame_unmap (frame);
938 gst_buffer_unmap (buf, map_info);
942 gst_cuda_buffer_copy_internal (GstBuffer * dst_buf,
943 GstCudaBufferCopyType dst_type, const GstVideoInfo * dst_info,
944 GstBuffer * src_buf, GstCudaBufferCopyType src_type,
945 const GstVideoInfo * src_info, GstCudaContext * context, CUstream stream)
947 GstVideoFrame dst_frame, src_frame;
948 gboolean ret = FALSE;
949 GstMapInfo dst_map, src_map;
951 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
953 memset (copy_params, 0, sizeof (copy_params));
954 memset (&dst_frame, 0, sizeof (GstVideoFrame));
955 memset (&src_frame, 0, sizeof (GstVideoFrame));
956 memset (&dst_map, 0, sizeof (GstMapInfo));
957 memset (&src_map, 0, sizeof (GstMapInfo));
959 if (!map_buffer_and_fill_copy2d (dst_buf, dst_info,
960 dst_type, &dst_frame, &dst_map, FALSE, copy_params)) {
961 GST_ERROR_OBJECT (context, "Failed to map output buffer");
965 if (!map_buffer_and_fill_copy2d (src_buf, src_info,
966 src_type, &src_frame, &src_map, TRUE, copy_params)) {
967 GST_ERROR_OBJECT (context, "Failed to map input buffer");
968 unmap_buffer_or_frame (dst_buf, &dst_frame, &dst_map);
972 if (!gst_cuda_context_push (context)) {
973 GST_ERROR_OBJECT (context, "Failed to push our context");
977 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (dst_info); i++) {
978 ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
980 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
985 gst_cuda_result (CuStreamSynchronize (stream));
986 gst_cuda_context_pop (NULL);
989 unmap_buffer_or_frame (dst_buf, &src_frame, &src_map);
990 unmap_buffer_or_frame (src_buf, &dst_frame, &dst_map);
995 #ifdef HAVE_NVCODEC_GST_GL
997 ensure_gl_interop (void)
999 guint device_count = 0;
1000 CUdevice device_list[1] = { 0, };
1003 cuda_ret = CuGLGetDevices (&device_count,
1004 device_list, 1, CU_GL_DEVICE_LIST_ALL);
1006 if (cuda_ret != CUDA_SUCCESS || device_count == 0)
1012 typedef struct _GLCopyData
1015 const GstVideoInfo *src_info;
1017 const GstVideoInfo *dst_info;
1019 gboolean pbo_to_cuda;
1020 GstCudaBufferCopyType copy_type;
1021 GstCudaContext *context;
1026 static GstCudaGraphicsResource *
1027 ensure_cuda_gl_graphics_resource (GstCudaContext * context, GstMemory * mem)
1030 GstCudaGraphicsResource *ret = NULL;
1032 if (!gst_is_gl_memory_pbo (mem)) {
1033 GST_WARNING_OBJECT (context, "memory is not GL PBO memory, %s",
1034 mem->allocator->mem_type);
1038 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
1039 ret = (GstCudaGraphicsResource *)
1040 gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
1043 GstGLMemoryPBO *pbo;
1047 ret = gst_cuda_graphics_resource_new (context,
1048 GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
1049 GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
1051 if (!gst_memory_map (mem, &info, (GstMapFlags) (GST_MAP_READ | GST_MAP_GL))) {
1052 GST_ERROR_OBJECT (context, "Failed to map gl memory");
1053 gst_cuda_graphics_resource_free (ret);
1057 pbo = (GstGLMemoryPBO *) mem;
1060 if (!gst_cuda_graphics_resource_register_gl_buffer (ret,
1061 buf->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
1062 GST_ERROR_OBJECT (context, "Failed to register gl buffer");
1063 gst_memory_unmap (mem, &info);
1064 gst_cuda_graphics_resource_free (ret);
1069 gst_memory_unmap (mem, &info);
1071 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, ret,
1072 (GDestroyNotify) gst_cuda_graphics_resource_free);
1079 gl_copy_thread_func (GstGLContext * gl_context, GLCopyData * data)
1081 GstCudaGraphicsResource *resources[GST_VIDEO_MAX_PLANES];
1082 guint num_resources;
1083 GstBuffer *gl_buf, *cuda_buf;
1084 GstVideoFrame cuda_frame;
1085 GstMapInfo cuda_map_info;
1086 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
1088 GstCudaContext *context = data->context;
1089 CUstream stream = data->stream;
1091 memset (copy_params, 0, sizeof (copy_params));
1092 memset (&cuda_frame, 0, sizeof (GstVideoFrame));
1093 memset (&cuda_map_info, 0, sizeof (GstMapInfo));
1097 /* Incompatible gl context */
1098 if (!ensure_gl_interop ())
1101 if (data->pbo_to_cuda) {
1102 gl_buf = data->src_buf;
1103 cuda_buf = data->dst_buf;
1105 if (!map_buffer_and_fill_copy2d (cuda_buf,
1106 data->dst_info, data->copy_type, &cuda_frame, &cuda_map_info,
1107 FALSE, copy_params)) {
1108 GST_ERROR_OBJECT (context, "Failed to map output CUDA buffer");
1112 gl_buf = data->dst_buf;
1113 cuda_buf = data->src_buf;
1115 if (!map_buffer_and_fill_copy2d (cuda_buf,
1116 data->src_info, data->copy_type, &cuda_frame, &cuda_map_info,
1117 TRUE, copy_params)) {
1118 GST_ERROR_OBJECT (context, "Failed to map input CUDA buffer");
1123 num_resources = gst_buffer_n_memory (gl_buf);
1124 g_assert (num_resources >= GST_VIDEO_INFO_N_PLANES (data->src_info));
1126 if (!gst_cuda_context_push (context)) {
1127 GST_ERROR_OBJECT (context, "Failed to push context");
1128 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1132 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->src_info); i++) {
1133 GstMemory *mem = gst_buffer_peek_memory (gl_buf, i);
1134 GstGLMemoryPBO *pbo;
1136 resources[i] = ensure_cuda_gl_graphics_resource (context, mem);
1140 pbo = (GstGLMemoryPBO *) mem;
1141 if (!data->pbo_to_cuda) {
1142 /* Need PBO -> texture */
1143 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
1146 GST_MINI_OBJECT_FLAG_SET (pbo->pbo,
1147 GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
1149 /* get the texture into the PBO */
1150 gst_gl_memory_pbo_upload_transfer (pbo);
1151 gst_gl_memory_pbo_download_transfer (pbo);
1155 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->src_info); i++) {
1156 CUgraphicsResource cuda_resource;
1157 CUdeviceptr dev_ptr;
1160 gsize width_in_bytes, height;
1162 if (data->pbo_to_cuda) {
1164 gst_cuda_graphics_resource_map (resources[i], stream,
1165 CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY);
1168 gst_cuda_graphics_resource_map (resources[i], stream,
1169 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1172 if (!cuda_resource) {
1173 GST_ERROR_OBJECT (context, "Failed to map graphics resource %d", i);
1177 if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&dev_ptr, &size,
1179 gst_cuda_graphics_resource_unmap (resources[i], stream);
1180 GST_ERROR_OBJECT (context, "Failed to get mapped pointer");
1184 if (data->pbo_to_cuda) {
1185 copy_params[i].srcMemoryType = CU_MEMORYTYPE_DEVICE;
1186 copy_params[i].srcDevice = dev_ptr;
1187 copy_params[i].srcPitch = GST_VIDEO_INFO_PLANE_STRIDE (data->src_info, i);
1189 width_in_bytes = GST_VIDEO_INFO_COMP_WIDTH (data->src_info, i) *
1190 GST_VIDEO_INFO_COMP_PSTRIDE (data->src_info, i);
1191 height = GST_VIDEO_INFO_COMP_HEIGHT (data->src_info, i);
1193 copy_params[i].dstMemoryType = CU_MEMORYTYPE_DEVICE;
1194 copy_params[i].dstDevice = dev_ptr;
1195 copy_params[i].dstPitch = GST_VIDEO_INFO_PLANE_STRIDE (data->dst_info, i);
1197 width_in_bytes = GST_VIDEO_INFO_COMP_WIDTH (data->dst_info, i) *
1198 GST_VIDEO_INFO_COMP_PSTRIDE (data->dst_info, i);
1199 height = GST_VIDEO_INFO_COMP_HEIGHT (data->dst_info, i);
1202 if (width_in_bytes < copy_params[i].WidthInBytes)
1203 copy_params[i].WidthInBytes = width_in_bytes;
1205 if (height < copy_params[i].Height)
1206 copy_params[i].Height = height;
1208 copy_ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
1209 gst_cuda_graphics_resource_unmap (resources[i], stream);
1212 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
1220 gst_cuda_result (CuStreamSynchronize (stream));
1221 gst_cuda_context_pop (NULL);
1222 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1226 cuda_copy_gl_interop (GstBuffer * dst_buf, const GstVideoInfo * dst_info,
1227 GstBuffer * src_buf, const GstVideoInfo * src_info,
1228 GstGLContext * gl_context, GstCudaContext * context, CUstream stream,
1229 gboolean pbo_to_cuda, GstCudaBufferCopyType copy_type)
1233 g_assert (copy_type == GST_CUDA_BUFFER_COPY_CUDA ||
1234 copy_type == GST_CUDA_BUFFER_COPY_NVMM);
1236 data.src_buf = src_buf;
1237 data.src_info = src_info;
1238 data.dst_buf = dst_buf;
1239 data.dst_info = dst_info;
1240 data.pbo_to_cuda = pbo_to_cuda;
1241 data.copy_type = copy_type;
1242 data.context = context;
1243 data.stream = stream;
1246 gst_gl_context_thread_add (gl_context,
1247 (GstGLContextThreadFunc) gl_copy_thread_func, &data);
1253 #ifdef HAVE_NVCODEC_GST_D3D11
1255 ensure_d3d11_interop (GstCudaContext * context, GstD3D11Device * device)
1257 guint device_count = 0;
1258 guint cuda_device_id;
1259 CUdevice device_list[1] = { 0, };
1262 g_object_get (context, "cuda-device-id", &cuda_device_id, NULL);
1264 cuda_ret = CuD3D11GetDevices (&device_count,
1265 device_list, 1, gst_d3d11_device_get_device_handle (device),
1266 CU_D3D11_DEVICE_LIST_ALL);
1268 if (cuda_ret != CUDA_SUCCESS || device_count == 0)
1271 if (device_list[0] != (CUdevice) cuda_device_id)
1277 static GstCudaGraphicsResource *
1278 ensure_cuda_d3d11_graphics_resource (GstCudaContext * context, GstMemory * mem)
1281 GstCudaGraphicsResource *ret = NULL;
1283 if (!gst_is_d3d11_memory (mem)) {
1284 GST_WARNING_OBJECT (context, "memory is not D3D11 memory, %s",
1285 mem->allocator->mem_type);
1289 quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
1290 ret = (GstCudaGraphicsResource *)
1291 gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
1294 ret = gst_cuda_graphics_resource_new (context,
1295 GST_OBJECT (GST_D3D11_MEMORY_CAST (mem)->device),
1296 GST_CUDA_GRAPHICS_RESOURCE_D3D11_RESOURCE);
1298 if (!gst_cuda_graphics_resource_register_d3d11_resource (ret,
1299 gst_d3d11_memory_get_resource_handle (GST_D3D11_MEMORY_CAST (mem)),
1300 CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LOAD_STORE)) {
1301 GST_ERROR_OBJECT (context, "failed to register d3d11 resource");
1302 gst_cuda_graphics_resource_free (ret);
1307 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, ret,
1308 (GDestroyNotify) gst_cuda_graphics_resource_free);
1315 cuda_copy_d3d11_interop (GstBuffer * dst_buf, const GstVideoInfo * dst_info,
1316 GstBuffer * src_buf, const GstVideoInfo * src_info, GstD3D11Device * device,
1317 GstCudaContext * context, CUstream stream, gboolean d3d11_to_cuda)
1319 GstCudaGraphicsResource *resources[GST_VIDEO_MAX_PLANES];
1320 D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
1321 guint num_resources;
1322 GstBuffer *d3d11_buf, *cuda_buf;
1323 GstVideoFrame d3d11_frame, cuda_frame;
1324 GstMapInfo cuda_map_info;
1325 CUDA_MEMCPY2D copy_params[GST_VIDEO_MAX_PLANES];
1327 gboolean ret = FALSE;
1329 memset (copy_params, 0, sizeof (copy_params));
1330 memset (&cuda_frame, 0, sizeof (GstVideoFrame));
1331 memset (&cuda_map_info, 0, sizeof (GstMapInfo));
1333 /* Incompatible d3d11 device */
1334 if (!ensure_d3d11_interop (context, device))
1337 if (d3d11_to_cuda) {
1338 d3d11_buf = src_buf;
1340 if (!gst_video_frame_map (&d3d11_frame, src_info, d3d11_buf,
1341 GST_MAP_READ | GST_MAP_D3D11)) {
1342 GST_ERROR_OBJECT (context, "Failed to map input D3D11 buffer");
1345 if (!map_buffer_and_fill_copy2d (cuda_buf,
1346 dst_info, GST_CUDA_BUFFER_COPY_CUDA, &cuda_frame, &cuda_map_info,
1347 FALSE, copy_params)) {
1348 GST_ERROR_OBJECT (context, "Failed to map output CUDA buffer");
1349 gst_video_frame_unmap (&d3d11_frame);
1353 d3d11_buf = dst_buf;
1355 if (!gst_video_frame_map (&d3d11_frame, dst_info, d3d11_buf,
1356 GST_MAP_WRITE | GST_MAP_D3D11)) {
1357 GST_ERROR_OBJECT (context, "Failed to map output D3D11 buffer");
1360 if (!map_buffer_and_fill_copy2d (cuda_buf,
1361 src_info, GST_CUDA_BUFFER_COPY_CUDA, &cuda_frame, &cuda_map_info,
1362 TRUE, copy_params)) {
1363 GST_ERROR_OBJECT (context, "Failed to map input CUDA buffer");
1364 gst_video_frame_unmap (&d3d11_frame);
1369 num_resources = gst_buffer_n_memory (d3d11_buf);
1370 g_assert (num_resources >= GST_VIDEO_FRAME_N_PLANES (&d3d11_frame));
1372 if (!gst_cuda_context_push (context)) {
1373 GST_ERROR_OBJECT (context, "Failed to push context");
1374 gst_video_frame_unmap (&d3d11_frame);
1375 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1379 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&d3d11_frame); i++) {
1380 GstMemory *mem = gst_buffer_peek_memory (d3d11_buf, i);
1382 resources[i] = ensure_cuda_d3d11_graphics_resource (context, mem);
1384 || !gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (mem),
1389 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&d3d11_frame); i++) {
1390 CUgraphicsResource cuda_resource;
1391 CUarray d3d11_array;
1394 if (d3d11_to_cuda) {
1396 gst_cuda_graphics_resource_map (resources[i], stream,
1397 CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY);
1400 gst_cuda_graphics_resource_map (resources[i], stream,
1401 CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
1404 if (!cuda_resource) {
1405 GST_ERROR_OBJECT (context, "Failed to map graphics resource %d", i);
1409 if (!gst_cuda_result (CuGraphicsSubResourceGetMappedArray (&d3d11_array,
1410 cuda_resource, 0, 0))) {
1411 gst_cuda_graphics_resource_unmap (resources[i], stream);
1412 GST_ERROR_OBJECT (context, "Failed to get mapped array");
1416 if (d3d11_to_cuda) {
1417 copy_params[i].srcMemoryType = CU_MEMORYTYPE_ARRAY;
1418 copy_params[i].srcArray = d3d11_array;
1419 copy_params[i].srcPitch =
1420 desc[i].Width * GST_VIDEO_FRAME_COMP_PSTRIDE (&d3d11_frame, i);
1422 copy_params[i].dstMemoryType = CU_MEMORYTYPE_ARRAY;
1423 copy_params[i].dstArray = d3d11_array;
1424 copy_params[i].dstPitch =
1425 desc[i].Width * GST_VIDEO_FRAME_COMP_PSTRIDE (&d3d11_frame, i);
1428 copy_ret = gst_cuda_result (CuMemcpy2DAsync (©_params[i], stream));
1429 gst_cuda_graphics_resource_unmap (resources[i], stream);
1432 GST_ERROR_OBJECT (context, "Failed to copy plane %d", i);
1440 gst_cuda_result (CuStreamSynchronize (stream));
1441 gst_cuda_context_pop (NULL);
1442 gst_video_frame_unmap (&d3d11_frame);
1443 unmap_buffer_or_frame (cuda_buf, &cuda_frame, &cuda_map_info);
1450 gst_cuda_buffer_copy (GstBuffer * dst, GstCudaBufferCopyType dst_type,
1451 const GstVideoInfo * dst_info, GstBuffer * src,
1452 GstCudaBufferCopyType src_type, const GstVideoInfo * src_info,
1453 GstCudaContext * context, CUstream stream)
1455 gboolean use_copy_2d = FALSE;
1456 GstMemory *dst_mem, *src_mem;
1457 #ifdef HAVE_NVCODEC_GST_D3D11
1458 D3D11_TEXTURE2D_DESC desc;
1460 GstCudaContext *cuda_context;
1462 g_return_val_if_fail (GST_IS_BUFFER (dst), FALSE);
1463 g_return_val_if_fail (dst_info != NULL, FALSE);
1464 g_return_val_if_fail (GST_IS_BUFFER (src), FALSE);
1465 g_return_val_if_fail (src_info != NULL, FALSE);
1466 g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), FALSE);
1468 if (dst_type == GST_CUDA_BUFFER_COPY_NVMM &&
1469 src_type == GST_CUDA_BUFFER_COPY_NVMM) {
1470 GST_ERROR_OBJECT (context, "Not supported copy NVMM -> NVMM");
1474 if (GST_VIDEO_INFO_FORMAT (dst_info) != GST_VIDEO_INFO_FORMAT (src_info)) {
1475 GST_ERROR_OBJECT (context,
1476 "Copy between different format is not supported");
1480 if (dst_type == GST_CUDA_BUFFER_COPY_CUDA ||
1481 dst_type == GST_CUDA_BUFFER_COPY_NVMM ||
1482 src_type == GST_CUDA_BUFFER_COPY_CUDA ||
1483 src_type == GST_CUDA_BUFFER_COPY_NVMM) {
1488 GST_TRACE_OBJECT (context, "Not a device memory, use system memory copy");
1489 return gst_cuda_buffer_fallback_copy (dst, dst_info, src, src_info);
1492 dst_mem = gst_buffer_peek_memory (dst, 0);
1493 src_mem = gst_buffer_peek_memory (src, 0);
1495 #ifdef HAVE_NVCODEC_GST_GL
1496 if (src_type == GST_CUDA_BUFFER_COPY_GL && gst_is_gl_memory_pbo (src_mem)) {
1497 GstGLMemory *gl_mem = (GstGLMemory *) src_mem;
1498 GstGLContext *gl_context = gl_mem->mem.context;
1499 GstCudaContext *cuda_context = context;
1501 if (dst_type == GST_CUDA_BUFFER_COPY_CUDA && gst_is_cuda_memory (dst_mem))
1502 cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1504 GST_TRACE_OBJECT (context, "GL -> %s",
1505 gst_cuda_buffery_copy_type_to_string (dst_type));
1507 return cuda_copy_gl_interop (dst, dst_info, src, src_info, gl_context,
1508 cuda_context, stream, TRUE, dst_type);
1511 if (dst_type == GST_CUDA_BUFFER_COPY_GL && gst_is_gl_memory_pbo (dst_mem)) {
1512 GstGLMemory *gl_mem = (GstGLMemory *) dst_mem;
1513 GstGLContext *gl_context = gl_mem->mem.context;
1514 GstCudaContext *cuda_context = context;
1516 if (src_type == GST_CUDA_BUFFER_COPY_CUDA && gst_is_cuda_memory (src_mem))
1517 cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1519 GST_TRACE_OBJECT (context, "%s -> GL",
1520 gst_cuda_buffery_copy_type_to_string (src_type));
1522 return cuda_copy_gl_interop (dst, dst_info, src, src_info, gl_context,
1523 cuda_context, stream, FALSE, src_type);
1527 #ifdef HAVE_NVCODEC_GST_D3D11
1528 if (src_type == GST_CUDA_BUFFER_COPY_D3D11 && gst_is_d3d11_memory (src_mem) &&
1529 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (src_mem), &desc)
1530 && desc.Usage == D3D11_USAGE_DEFAULT && gst_is_cuda_memory (dst_mem)) {
1531 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (src_mem);
1532 GstD3D11Device *device = dmem->device;
1533 GstCudaContext *cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1536 GST_TRACE_OBJECT (context, "D3D11 -> CUDA");
1538 gst_d3d11_device_lock (device);
1539 ret = cuda_copy_d3d11_interop (dst, dst_info, src, src_info, device,
1540 cuda_context, stream, TRUE);
1541 gst_d3d11_device_unlock (device);
1546 if (dst_type == GST_CUDA_BUFFER_COPY_D3D11 && gst_is_d3d11_memory (dst_mem) &&
1547 gst_d3d11_memory_get_texture_desc (GST_D3D11_MEMORY_CAST (dst_mem), &desc)
1548 && desc.Usage == D3D11_USAGE_DEFAULT && gst_is_cuda_memory (src_mem)) {
1549 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (dst_mem);
1550 GstD3D11Device *device = dmem->device;
1551 GstCudaContext *cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1554 GST_TRACE_OBJECT (context, "CUDA -> D3D11");
1556 gst_d3d11_device_lock (device);
1557 ret = cuda_copy_d3d11_interop (dst, dst_info, src, src_info, device,
1558 cuda_context, stream, FALSE);
1559 gst_d3d11_device_unlock (device);
1565 if (gst_is_cuda_memory (dst_mem)) {
1566 cuda_context = GST_CUDA_MEMORY_CAST (dst_mem)->context;
1567 } else if (gst_is_cuda_memory (src_mem)) {
1568 cuda_context = GST_CUDA_MEMORY_CAST (src_mem)->context;
1570 cuda_context = context;
1573 GST_TRACE_OBJECT (context, "%s -> %s",
1574 gst_cuda_buffery_copy_type_to_string (src_type),
1575 gst_cuda_buffery_copy_type_to_string (dst_type));
1577 return gst_cuda_buffer_copy_internal (dst, dst_type, dst_info,
1578 src, src_type, src_info, cuda_context, stream);