/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/video/gstvideopool.c
Line | Count | Source |
1 | | /* GStreamer |
2 | | * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.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 | | #ifdef HAVE_CONFIG_H |
20 | | #include "config.h" |
21 | | #endif |
22 | | |
23 | | #include "gst/video/gstvideometa.h" |
24 | | #include "gst/video/gstvideopool.h" |
25 | | |
26 | | |
27 | | GST_DEBUG_CATEGORY_STATIC (gst_video_pool_debug); |
28 | | #define GST_CAT_DEFAULT gst_video_pool_debug |
29 | | |
30 | | /** |
31 | | * SECTION:gstvideopool |
32 | | * @title: GstVideoBufferPool |
33 | | * @short_description: GstBufferPool for raw video buffers |
34 | | * @see_also: #GstBufferPool |
35 | | * |
36 | | * Special GstBufferPool subclass for raw video buffers. |
37 | | * |
38 | | * Allows configuration of video-specific requirements such as |
39 | | * stride alignments or pixel padding, and can also be configured |
40 | | * to automatically add #GstVideoMeta to the buffers. |
41 | | */ |
42 | | |
43 | | /** |
44 | | * gst_buffer_pool_config_set_video_alignment: |
45 | | * @config: a #GstStructure |
46 | | * @align: a #GstVideoAlignment |
47 | | * |
48 | | * Set the video alignment in @align to the bufferpool configuration |
49 | | * @config |
50 | | */ |
51 | | void |
52 | | gst_buffer_pool_config_set_video_alignment (GstStructure * config, |
53 | | const GstVideoAlignment * align) |
54 | 0 | { |
55 | 0 | g_return_if_fail (config != NULL); |
56 | 0 | g_return_if_fail (align != NULL); |
57 | | |
58 | 0 | gst_structure_set (config, |
59 | 0 | "padding-top", G_TYPE_UINT, align->padding_top, |
60 | 0 | "padding-bottom", G_TYPE_UINT, align->padding_bottom, |
61 | 0 | "padding-left", G_TYPE_UINT, align->padding_left, |
62 | 0 | "padding-right", G_TYPE_UINT, align->padding_right, |
63 | 0 | "stride-align0", G_TYPE_UINT, align->stride_align[0], |
64 | 0 | "stride-align1", G_TYPE_UINT, align->stride_align[1], |
65 | 0 | "stride-align2", G_TYPE_UINT, align->stride_align[2], |
66 | 0 | "stride-align3", G_TYPE_UINT, align->stride_align[3], NULL); |
67 | 0 | } |
68 | | |
69 | | /** |
70 | | * gst_buffer_pool_config_get_video_alignment: |
71 | | * @config: a #GstStructure |
72 | | * @align: a #GstVideoAlignment |
73 | | * |
74 | | * Get the video alignment from the bufferpool configuration @config in |
75 | | * in @align |
76 | | * |
77 | | * Returns: %TRUE if @config could be parsed correctly. |
78 | | */ |
79 | | gboolean |
80 | | gst_buffer_pool_config_get_video_alignment (const GstStructure * config, |
81 | | GstVideoAlignment * align) |
82 | 0 | { |
83 | 0 | g_return_val_if_fail (config != NULL, FALSE); |
84 | 0 | g_return_val_if_fail (align != NULL, FALSE); |
85 | | |
86 | 0 | return gst_structure_get (config, |
87 | 0 | "padding-top", G_TYPE_UINT, &align->padding_top, |
88 | 0 | "padding-bottom", G_TYPE_UINT, &align->padding_bottom, |
89 | 0 | "padding-left", G_TYPE_UINT, &align->padding_left, |
90 | 0 | "padding-right", G_TYPE_UINT, &align->padding_right, |
91 | 0 | "stride-align0", G_TYPE_UINT, &align->stride_align[0], |
92 | 0 | "stride-align1", G_TYPE_UINT, &align->stride_align[1], |
93 | 0 | "stride-align2", G_TYPE_UINT, &align->stride_align[2], |
94 | 0 | "stride-align3", G_TYPE_UINT, &align->stride_align[3], NULL); |
95 | 0 | } |
96 | | |
97 | | /* bufferpool */ |
98 | | struct _GstVideoBufferPoolPrivate |
99 | | { |
100 | | GstVideoInfo info; |
101 | | GstVideoAlignment video_align; |
102 | | gboolean add_videometa; |
103 | | gboolean need_alignment; |
104 | | GstAllocator *allocator; |
105 | | GstAllocationParams params; |
106 | | }; |
107 | | |
108 | | static void gst_video_buffer_pool_finalize (GObject * object); |
109 | | |
110 | 0 | #define gst_video_buffer_pool_parent_class parent_class |
111 | 0 | G_DEFINE_TYPE_WITH_PRIVATE (GstVideoBufferPool, gst_video_buffer_pool, |
112 | 0 | GST_TYPE_BUFFER_POOL); |
113 | 0 |
|
114 | 0 | static const gchar ** |
115 | 0 | video_buffer_pool_get_options (GstBufferPool * pool) |
116 | 0 | { |
117 | 0 | static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, |
118 | 0 | GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL |
119 | 0 | }; |
120 | 0 | return options; |
121 | 0 | } |
122 | | |
123 | | static gboolean |
124 | | video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) |
125 | 0 | { |
126 | 0 | GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool); |
127 | 0 | GstVideoBufferPoolPrivate *priv = vpool->priv; |
128 | 0 | GstVideoInfo info; |
129 | 0 | GstCaps *caps; |
130 | 0 | guint size, min_buffers, max_buffers; |
131 | 0 | gint width, height; |
132 | 0 | GstAllocator *allocator; |
133 | 0 | GstAllocationParams params; |
134 | |
|
135 | 0 | if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, |
136 | 0 | &max_buffers)) |
137 | 0 | goto wrong_config; |
138 | | |
139 | 0 | if (caps == NULL) |
140 | 0 | goto no_caps; |
141 | | |
142 | | /* now parse the caps from the config */ |
143 | 0 | if (gst_video_is_dma_drm_caps (caps)) { |
144 | 0 | GstVideoInfoDmaDrm drm_info; |
145 | 0 | if (!gst_video_info_dma_drm_from_caps (&drm_info, caps)) |
146 | 0 | goto wrong_caps; |
147 | | |
148 | 0 | if (GST_VIDEO_INFO_FORMAT (&drm_info.vinfo) == GST_VIDEO_FORMAT_DMA_DRM) |
149 | 0 | goto wrong_caps; |
150 | | |
151 | 0 | info = drm_info.vinfo; |
152 | 0 | } else { |
153 | 0 | if (!gst_video_info_from_caps (&info, caps)) |
154 | 0 | goto wrong_caps; |
155 | 0 | } |
156 | | |
157 | 0 | if (size < info.size) |
158 | 0 | goto wrong_size; |
159 | | |
160 | 0 | if (!gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms)) |
161 | 0 | goto wrong_config; |
162 | | |
163 | 0 | width = info.width; |
164 | 0 | height = info.height; |
165 | |
|
166 | 0 | GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps); |
167 | |
|
168 | 0 | priv->params = params; |
169 | 0 | if (priv->allocator) |
170 | 0 | gst_object_unref (priv->allocator); |
171 | 0 | if ((priv->allocator = allocator)) |
172 | 0 | gst_object_ref (allocator); |
173 | | |
174 | | /* enable metadata based on config of the pool */ |
175 | 0 | priv->add_videometa = |
176 | 0 | gst_buffer_pool_config_has_option (config, |
177 | 0 | GST_BUFFER_POOL_OPTION_VIDEO_META); |
178 | | |
179 | | /* parse extra alignment info */ |
180 | 0 | priv->need_alignment = gst_buffer_pool_config_has_option (config, |
181 | 0 | GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); |
182 | |
|
183 | 0 | if (priv->need_alignment && priv->add_videometa) { |
184 | 0 | guint max_align, n; |
185 | |
|
186 | 0 | gst_buffer_pool_config_get_video_alignment (config, &priv->video_align); |
187 | | |
188 | | /* ensure GstAllocationParams alignment is compatible with video alignment */ |
189 | 0 | max_align = priv->params.align; |
190 | 0 | for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n) |
191 | 0 | max_align |= priv->video_align.stride_align[n]; |
192 | |
|
193 | 0 | for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n) |
194 | 0 | priv->video_align.stride_align[n] = max_align; |
195 | | |
196 | | /* apply the alignment to the info */ |
197 | 0 | if (!gst_video_info_align (&info, &priv->video_align)) |
198 | 0 | goto failed_to_align; |
199 | | |
200 | 0 | gst_buffer_pool_config_set_video_alignment (config, &priv->video_align); |
201 | |
|
202 | 0 | if (priv->params.align < max_align) { |
203 | 0 | GST_WARNING_OBJECT (pool, "allocation params alignment %u is smaller " |
204 | 0 | "than the max specified video stride alignment %u, fixing", |
205 | 0 | (guint) priv->params.align, max_align); |
206 | 0 | priv->params.align = max_align; |
207 | 0 | gst_buffer_pool_config_set_allocator (config, allocator, &priv->params); |
208 | 0 | } |
209 | 0 | } |
210 | 0 | info.size = MAX (size, info.size); |
211 | 0 | priv->info = info; |
212 | |
|
213 | 0 | gst_buffer_pool_config_set_params (config, caps, info.size, min_buffers, |
214 | 0 | max_buffers); |
215 | |
|
216 | 0 | return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config); |
217 | | |
218 | | /* ERRORS */ |
219 | 0 | wrong_config: |
220 | 0 | { |
221 | 0 | GST_WARNING_OBJECT (pool, "invalid config"); |
222 | 0 | return FALSE; |
223 | 0 | } |
224 | 0 | no_caps: |
225 | 0 | { |
226 | 0 | GST_WARNING_OBJECT (pool, "no caps in config"); |
227 | 0 | return FALSE; |
228 | 0 | } |
229 | 0 | wrong_caps: |
230 | 0 | { |
231 | 0 | GST_WARNING_OBJECT (pool, |
232 | 0 | "failed getting geometry from caps %" GST_PTR_FORMAT, caps); |
233 | 0 | return FALSE; |
234 | 0 | } |
235 | 0 | wrong_size: |
236 | 0 | { |
237 | 0 | GST_WARNING_OBJECT (pool, |
238 | 0 | "Provided size is to small for the caps: %u < %" G_GSIZE_FORMAT, size, |
239 | 0 | info.size); |
240 | 0 | gst_buffer_pool_config_set_params (config, caps, info.size, min_buffers, |
241 | 0 | max_buffers); |
242 | 0 | return FALSE; |
243 | 0 | } |
244 | 0 | failed_to_align: |
245 | 0 | { |
246 | 0 | GST_WARNING_OBJECT (pool, "Failed to align"); |
247 | 0 | return FALSE; |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | static GstFlowReturn |
252 | | video_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, |
253 | | GstBufferPoolAcquireParams * params) |
254 | 0 | { |
255 | 0 | GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool); |
256 | 0 | GstVideoBufferPoolPrivate *priv = vpool->priv; |
257 | 0 | GstVideoInfo *info; |
258 | |
|
259 | 0 | info = &priv->info; |
260 | |
|
261 | 0 | GST_DEBUG_OBJECT (pool, "alloc %" G_GSIZE_FORMAT, info->size); |
262 | |
|
263 | 0 | *buffer = |
264 | 0 | gst_buffer_new_allocate (priv->allocator, info->size, &priv->params); |
265 | 0 | if (*buffer == NULL) |
266 | 0 | goto no_memory; |
267 | | |
268 | 0 | if (priv->add_videometa) { |
269 | 0 | GST_DEBUG_OBJECT (pool, "adding GstVideoMeta"); |
270 | |
|
271 | 0 | gst_buffer_add_video_meta_full (*buffer, GST_VIDEO_FRAME_FLAG_NONE, |
272 | 0 | GST_VIDEO_INFO_FORMAT (info), |
273 | 0 | GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), |
274 | 0 | GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride); |
275 | 0 | } |
276 | |
|
277 | 0 | return GST_FLOW_OK; |
278 | | |
279 | | /* ERROR */ |
280 | 0 | no_memory: |
281 | 0 | { |
282 | 0 | GST_WARNING_OBJECT (pool, "can't create memory"); |
283 | 0 | return GST_FLOW_ERROR; |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | /** |
288 | | * gst_video_buffer_pool_new: |
289 | | * |
290 | | * Create a new bufferpool that can allocate video frames. This bufferpool |
291 | | * supports all the video bufferpool options. |
292 | | * |
293 | | * Returns: (transfer full): a new #GstBufferPool to allocate video frames |
294 | | */ |
295 | | GstBufferPool * |
296 | | gst_video_buffer_pool_new (void) |
297 | 0 | { |
298 | 0 | GstVideoBufferPool *pool; |
299 | |
|
300 | 0 | pool = g_object_new (GST_TYPE_VIDEO_BUFFER_POOL, NULL); |
301 | 0 | gst_object_ref_sink (pool); |
302 | |
|
303 | 0 | GST_LOG_OBJECT (pool, "new video buffer pool %p", pool); |
304 | |
|
305 | 0 | return GST_BUFFER_POOL_CAST (pool); |
306 | 0 | } |
307 | | |
308 | | static void |
309 | | gst_video_buffer_pool_class_init (GstVideoBufferPoolClass * klass) |
310 | 0 | { |
311 | 0 | GObjectClass *gobject_class = (GObjectClass *) klass; |
312 | 0 | GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; |
313 | |
|
314 | 0 | gobject_class->finalize = gst_video_buffer_pool_finalize; |
315 | |
|
316 | 0 | gstbufferpool_class->get_options = video_buffer_pool_get_options; |
317 | 0 | gstbufferpool_class->set_config = video_buffer_pool_set_config; |
318 | 0 | gstbufferpool_class->alloc_buffer = video_buffer_pool_alloc; |
319 | |
|
320 | 0 | GST_DEBUG_CATEGORY_INIT (gst_video_pool_debug, "videopool", 0, |
321 | 0 | "videopool object"); |
322 | 0 | } |
323 | | |
324 | | static void |
325 | | gst_video_buffer_pool_init (GstVideoBufferPool * pool) |
326 | 0 | { |
327 | 0 | pool->priv = gst_video_buffer_pool_get_instance_private (pool); |
328 | 0 | } |
329 | | |
330 | | static void |
331 | | gst_video_buffer_pool_finalize (GObject * object) |
332 | 0 | { |
333 | 0 | GstVideoBufferPool *pool = GST_VIDEO_BUFFER_POOL_CAST (object); |
334 | 0 | GstVideoBufferPoolPrivate *priv = pool->priv; |
335 | |
|
336 | 0 | GST_LOG_OBJECT (pool, "finalize video buffer pool %p", pool); |
337 | |
|
338 | 0 | if (priv->allocator) |
339 | 0 | gst_object_unref (priv->allocator); |
340 | |
|
341 | 0 | G_OBJECT_CLASS (gst_video_buffer_pool_parent_class)->finalize (object); |
342 | 0 | } |