• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "gstcudabufferpool.h"
25 #include "gstcudacontext.h"
26 #include "gstcudamemory.h"
27 
28 GST_DEBUG_CATEGORY_STATIC (gst_cuda_buffer_pool_debug);
29 #define GST_CAT_DEFAULT gst_cuda_buffer_pool_debug
30 
31 struct _GstCudaBufferPoolPrivate
32 {
33   GstCudaContext *context;
34   GstAllocator *allocator;
35   GstVideoInfo info;
36   gboolean add_videometa;
37   gboolean need_alignment;
38   GstCudaAllocationParams params;
39 };
40 
41 #define gst_cuda_buffer_pool_parent_class parent_class
42 G_DEFINE_TYPE_WITH_PRIVATE (GstCudaBufferPool, gst_cuda_buffer_pool,
43     GST_TYPE_BUFFER_POOL);
44 
45 static const gchar **
gst_cuda_buffer_pool_get_options(GstBufferPool * pool)46 gst_cuda_buffer_pool_get_options (GstBufferPool * pool)
47 {
48   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
49     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
50   };
51 
52   return options;
53 }
54 
55 static gboolean
gst_cuda_buffer_pool_set_config(GstBufferPool * pool,GstStructure * config)56 gst_cuda_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
57 {
58   GstCudaBufferPool *cuda_pool = GST_CUDA_BUFFER_POOL_CAST (pool);
59   GstCudaBufferPoolPrivate *priv = cuda_pool->priv;
60   GstCaps *caps = NULL;
61   guint size, min_buffers, max_buffers;
62   guint max_align, n;
63   GstAllocator *allocator = NULL;
64   GstAllocationParams *params = (GstAllocationParams *) & priv->params;
65   GstVideoInfo *info = &priv->params.info;
66 
67   if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
68           &max_buffers))
69     goto wrong_config;
70 
71   if (caps == NULL)
72     goto no_caps;
73 
74   if (!gst_buffer_pool_config_get_allocator (config, &allocator, params))
75     goto wrong_config;
76 
77   /* now parse the caps from the config */
78   if (!gst_video_info_from_caps (info, caps))
79     goto wrong_caps;
80 
81   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT,
82       GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), caps);
83 
84   gst_clear_object (&priv->allocator);
85 
86   if (allocator) {
87     if (!GST_IS_CUDA_ALLOCATOR (allocator)) {
88       goto wrong_allocator;
89     } else {
90       priv->allocator = gst_object_ref (allocator);
91     }
92   } else {
93     allocator = priv->allocator = gst_cuda_allocator_new (priv->context);
94     if (G_UNLIKELY (priv->allocator == NULL))
95       goto no_allocator;
96   }
97 
98   priv->add_videometa = gst_buffer_pool_config_has_option (config,
99       GST_BUFFER_POOL_OPTION_VIDEO_META);
100 
101   priv->need_alignment = gst_buffer_pool_config_has_option (config,
102       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
103 
104   max_align = params->align;
105 
106   /* do memory align */
107   if (priv->need_alignment && priv->add_videometa) {
108     GstVideoAlignment valign;
109 
110     gst_buffer_pool_config_get_video_alignment (config, &valign);
111 
112     for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
113       max_align |= valign.stride_align[n];
114 
115     for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
116       valign.stride_align[n] = max_align;
117 
118     if (!gst_video_info_align (info, &valign))
119       goto failed_to_align;
120 
121     gst_buffer_pool_config_set_video_alignment (config, &valign);
122   }
123 
124   if (params->align < max_align) {
125     GST_WARNING_OBJECT (pool, "allocation params alignment %u is smaller "
126         "than the max specified video stride alignment %u, fixing",
127         (guint) params->align, max_align);
128 
129     params->align = max_align;
130     gst_buffer_pool_config_set_allocator (config, allocator, params);
131   }
132 
133   gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (info),
134       min_buffers, max_buffers);
135 
136   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
137 
138   /* ERRORS */
139 wrong_config:
140   {
141     GST_WARNING_OBJECT (pool, "invalid config");
142     return FALSE;
143   }
144 no_caps:
145   {
146     GST_WARNING_OBJECT (pool, "no caps in config");
147     return FALSE;
148   }
149 wrong_caps:
150   {
151     GST_WARNING_OBJECT (pool,
152         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
153     return FALSE;
154   }
155 no_allocator:
156   {
157     GST_WARNING_OBJECT (pool, "Could not create new CUDA allocator");
158     return FALSE;
159   }
160 wrong_allocator:
161   {
162     GST_WARNING_OBJECT (pool, "Incorrect allocator type for this pool");
163     return FALSE;
164   }
165 failed_to_align:
166   {
167     GST_WARNING_OBJECT (pool, "Failed to align");
168     return FALSE;
169   }
170 }
171 
172 static GstFlowReturn
gst_cuda_buffer_pool_alloc(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)173 gst_cuda_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
174     GstBufferPoolAcquireParams * params)
175 {
176   GstCudaBufferPool *cuda_pool = GST_CUDA_BUFFER_POOL_CAST (pool);
177   GstCudaBufferPoolPrivate *priv = cuda_pool->priv;
178   GstVideoInfo *info;
179   GstBuffer *cuda;
180   GstMemory *mem;
181 
182   info = &priv->params.info;
183 
184   cuda = gst_buffer_new ();
185 
186   mem = gst_cuda_allocator_alloc (GST_ALLOCATOR_CAST (priv->allocator),
187       GST_VIDEO_INFO_SIZE (info), &priv->params);
188 
189   if (mem == NULL) {
190     gst_buffer_unref (cuda);
191     GST_WARNING_OBJECT (pool, "Cannot create CUDA memory");
192     return GST_FLOW_ERROR;
193   }
194   gst_buffer_append_memory (cuda, mem);
195 
196   if (priv->add_videometa) {
197     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
198     gst_buffer_add_video_meta_full (cuda, GST_VIDEO_FRAME_FLAG_NONE,
199         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
200         GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
201         info->offset, info->stride);
202   }
203 
204   *buffer = cuda;
205 
206   return GST_FLOW_OK;
207 }
208 
209 GstBufferPool *
gst_cuda_buffer_pool_new(GstCudaContext * context)210 gst_cuda_buffer_pool_new (GstCudaContext * context)
211 {
212   GstCudaBufferPool *pool;
213 
214   pool = g_object_new (GST_TYPE_CUDA_BUFFER_POOL, NULL);
215   gst_object_ref_sink (pool);
216 
217   pool->priv->context = gst_object_ref (context);
218 
219   GST_LOG_OBJECT (pool, "new CUDA buffer pool %p", pool);
220 
221   return GST_BUFFER_POOL_CAST (pool);
222 }
223 
224 static void
gst_cuda_buffer_pool_dispose(GObject * object)225 gst_cuda_buffer_pool_dispose (GObject * object)
226 {
227   GstCudaBufferPool *pool = GST_CUDA_BUFFER_POOL_CAST (object);
228   GstCudaBufferPoolPrivate *priv = pool->priv;
229 
230   GST_LOG_OBJECT (pool, "finalize CUDA buffer pool %p", pool);
231 
232   gst_clear_object (&priv->allocator);
233   gst_clear_object (&priv->context);
234 
235   G_OBJECT_CLASS (parent_class)->dispose (object);
236 }
237 
238 
239 static void
gst_cuda_buffer_pool_class_init(GstCudaBufferPoolClass * klass)240 gst_cuda_buffer_pool_class_init (GstCudaBufferPoolClass * klass)
241 {
242   GObjectClass *gobject_class = (GObjectClass *) klass;
243   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
244 
245   gobject_class->dispose = gst_cuda_buffer_pool_dispose;
246 
247   gstbufferpool_class->get_options = gst_cuda_buffer_pool_get_options;
248   gstbufferpool_class->set_config = gst_cuda_buffer_pool_set_config;
249   gstbufferpool_class->alloc_buffer = gst_cuda_buffer_pool_alloc;
250 
251   GST_DEBUG_CATEGORY_INIT (gst_cuda_buffer_pool_debug, "cudabufferpool", 0,
252       "CUDA Buffer Pool");
253 }
254 
255 static void
gst_cuda_buffer_pool_init(GstCudaBufferPool * pool)256 gst_cuda_buffer_pool_init (GstCudaBufferPool * pool)
257 {
258   pool->priv = gst_cuda_buffer_pool_get_instance_private (pool);
259 }
260