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