c56a2ccf6f15d0106ae33cfc2408d058eb29cb17
[platform/upstream/gstreamer.git] / gst-libs / gst / video / gstvideopool.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gst/video/gstvideometa.h"
21 #include "gst/video/gstvideopool.h"
22
23 /**
24  * gst_video_alignment_reset:
25  * @align: a #GstVideoAlignment
26  *
27  * Set @align to its default values with no padding and no alignment.
28  */
29 void
30 gst_video_alignment_reset (GstVideoAlignment * align)
31 {
32   gint i;
33
34   g_return_if_fail (align != NULL);
35
36   align->padding_top = 0;
37   align->padding_bottom = 0;
38   align->padding_left = 0;
39   align->padding_right = 0;
40   for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
41     align->stride_align[i] = 0;
42 }
43
44 /**
45  * gst_buffer_pool_config_set_video_alignment:
46  * @config: a #GstStructure
47  * @align: a #GstVideoAlignment
48  *
49  * Set the video alignment in @align to the bufferpool configuration
50  * @config
51  */
52 void
53 gst_buffer_pool_config_set_video_alignment (GstStructure * config,
54     GstVideoAlignment * align)
55 {
56   g_return_if_fail (config != NULL);
57   g_return_if_fail (align != NULL);
58
59   gst_structure_set (config,
60       "padding-top", G_TYPE_UINT, align->padding_top,
61       "padding-bottom", G_TYPE_UINT, align->padding_bottom,
62       "padding-left", G_TYPE_UINT, align->padding_left,
63       "padding-right", G_TYPE_UINT, align->padding_right,
64       "stride-align0", G_TYPE_UINT, align->stride_align[0],
65       "stride-align1", G_TYPE_UINT, align->stride_align[1],
66       "stride-align2", G_TYPE_UINT, align->stride_align[2],
67       "stride-align3", G_TYPE_UINT, align->stride_align[3], NULL);
68 }
69
70 /**
71  * gst_buffer_pool_config_get_video_alignment:
72  * @config: a #GstStructure
73  * @align: a #GstVideoAlignment
74  *
75  * Get the video alignment from the bufferpool configuration @config in
76  * in @align
77  *
78  * Returns: #TRUE if @config could be parsed correctly.
79  */
80 gboolean
81 gst_buffer_pool_config_get_video_alignment (GstStructure * config,
82     GstVideoAlignment * align)
83 {
84   g_return_val_if_fail (config != NULL, FALSE);
85   g_return_val_if_fail (align != NULL, FALSE);
86
87   return gst_structure_get (config,
88       "padding-top", G_TYPE_UINT, &align->padding_top,
89       "padding-bottom", G_TYPE_UINT, &align->padding_bottom,
90       "padding-left", G_TYPE_UINT, &align->padding_left,
91       "padding-right", G_TYPE_UINT, &align->padding_right,
92       "stride-align0", G_TYPE_UINT, &align->stride_align[0],
93       "stride-align1", G_TYPE_UINT, &align->stride_align[1],
94       "stride-align2", G_TYPE_UINT, &align->stride_align[2],
95       "stride-align3", G_TYPE_UINT, &align->stride_align[3], NULL);
96 }
97
98 static void
99 gst_video_info_align (GstVideoInfo * info, GstVideoAlignment * align)
100 {
101   const GstVideoFormatInfo *vinfo = info->finfo;
102   gint width, height;
103   gint padded_width, padded_height;
104   gint i;
105
106   width = GST_VIDEO_INFO_WIDTH (info);
107   height = GST_VIDEO_INFO_HEIGHT (info);
108
109   GST_LOG ("padding %u-%ux%u-%u", align->padding_top,
110       align->padding_left, align->padding_right, align->padding_bottom);
111
112   /* add the padding */
113   padded_width = width + align->padding_left + align->padding_right;
114   padded_height = height + align->padding_top + align->padding_bottom;
115
116   gst_video_info_set_format (info, GST_VIDEO_INFO_FORMAT (info),
117       padded_width, padded_height);
118
119   info->width = width;
120   info->height = height;
121
122   /* FIXME, not quite correct, NV12 would apply the vedge twice on the second
123    * plane */
124   for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (info); i++) {
125     gint vedge, hedge, plane;
126
127     hedge = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vinfo, i, align->padding_left);
128     vedge = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo, i, align->padding_top);
129     plane = GST_VIDEO_FORMAT_INFO_PLANE (vinfo, i);
130
131     GST_DEBUG ("plane %d: hedge %d vedge %d align %d", plane, hedge, vedge,
132         align->stride_align[i]);
133
134     info->offset[plane] += (vedge * info->stride[plane]) + hedge;
135   }
136 }
137
138 /* bufferpool */
139 struct _GstVideoBufferPoolPrivate
140 {
141   GstCaps *caps;
142   GstVideoInfo info;
143   GstVideoAlignment video_align;
144   gboolean add_videometa;
145   gboolean need_alignment;
146   GstAllocator *allocator;
147   GstAllocationParams params;
148 };
149
150 static void gst_video_buffer_pool_finalize (GObject * object);
151
152 #define GST_VIDEO_BUFFER_POOL_GET_PRIVATE(obj)  \
153    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VIDEO_BUFFER_POOL, GstVideoBufferPoolPrivate))
154
155 #define gst_video_buffer_pool_parent_class parent_class
156 G_DEFINE_TYPE (GstVideoBufferPool, gst_video_buffer_pool, GST_TYPE_BUFFER_POOL);
157
158 static const gchar **
159 video_buffer_pool_get_options (GstBufferPool * pool)
160 {
161   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
162     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
163   };
164   return options;
165 }
166
167 static gboolean
168 video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
169 {
170   GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool);
171   GstVideoBufferPoolPrivate *priv = vpool->priv;
172   GstVideoInfo info;
173   const GstCaps *caps;
174   gint width, height;
175   GstAllocator *allocator;
176   GstAllocationParams params;
177
178   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
179     goto wrong_config;
180
181   if (caps == NULL)
182     goto no_caps;
183
184   /* now parse the caps from the config */
185   if (!gst_video_info_from_caps (&info, caps))
186     goto wrong_caps;
187
188   if (!gst_buffer_pool_config_get_allocator (config, &allocator, &params))
189     goto wrong_config;
190
191   width = info.width;
192   height = info.height;
193
194   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps);
195
196   if (priv->caps)
197     gst_caps_unref (priv->caps);
198   priv->caps = gst_caps_copy (caps);
199
200   priv->params = params;
201   if (priv->allocator)
202     gst_allocator_unref (priv->allocator);
203   if ((priv->allocator = allocator))
204     gst_allocator_ref (allocator);
205
206   /* enable metadata based on config of the pool */
207   priv->add_videometa =
208       gst_buffer_pool_config_has_option (config,
209       GST_BUFFER_POOL_OPTION_VIDEO_META);
210
211   /* parse extra alignment info */
212   priv->need_alignment = gst_buffer_pool_config_has_option (config,
213       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
214
215   if (priv->need_alignment && priv->add_videometa) {
216     /* get an apply the alignment to the info */
217     gst_buffer_pool_config_get_video_alignment (config, &priv->video_align);
218     gst_video_info_align (&info, &priv->video_align);
219   }
220   priv->info = info;
221
222   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
223
224   /* ERRORS */
225 wrong_config:
226   {
227     GST_WARNING_OBJECT (pool, "invalid config");
228     return FALSE;
229   }
230 no_caps:
231   {
232     GST_WARNING_OBJECT (pool, "no caps in config");
233     return FALSE;
234   }
235 wrong_caps:
236   {
237     GST_WARNING_OBJECT (pool,
238         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
239     return FALSE;
240   }
241 }
242
243 static GstFlowReturn
244 video_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
245     GstBufferPoolAcquireParams * params)
246 {
247   GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool);
248   GstVideoBufferPoolPrivate *priv = vpool->priv;
249   GstVideoInfo *info;
250
251   info = &priv->info;
252
253   GST_DEBUG_OBJECT (pool, "alloc %" G_GSIZE_FORMAT, info->size);
254
255   *buffer =
256       gst_buffer_new_allocate (priv->allocator, info->size, &priv->params);
257   if (*buffer == NULL)
258     goto no_memory;
259
260   if (priv->add_videometa) {
261     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
262
263     gst_buffer_add_video_meta_full (*buffer, 0, GST_VIDEO_INFO_FORMAT (info),
264         GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
265         GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride);
266   }
267
268   return GST_FLOW_OK;
269
270   /* ERROR */
271 no_memory:
272   {
273     GST_WARNING_OBJECT (pool, "can't create memory");
274     return GST_FLOW_ERROR;
275   }
276 }
277
278 /**
279  * gst_video_buffer_pool_new:
280  *
281  * Create a new bufferpool that can allocate video frames. This bufferpool
282  * supports all the video bufferpool options.
283  *
284  * Returns: a new #GstBufferPool to allocate video frames
285  */
286 GstBufferPool *
287 gst_video_buffer_pool_new ()
288 {
289   GstVideoBufferPool *pool;
290
291   pool = g_object_new (GST_TYPE_VIDEO_BUFFER_POOL, NULL);
292
293   GST_LOG_OBJECT (pool, "new video buffer pool %p", pool);
294
295   return GST_BUFFER_POOL_CAST (pool);
296 }
297
298 static void
299 gst_video_buffer_pool_class_init (GstVideoBufferPoolClass * klass)
300 {
301   GObjectClass *gobject_class = (GObjectClass *) klass;
302   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
303
304   g_type_class_add_private (klass, sizeof (GstVideoBufferPoolPrivate));
305
306   gobject_class->finalize = gst_video_buffer_pool_finalize;
307
308   gstbufferpool_class->get_options = video_buffer_pool_get_options;
309   gstbufferpool_class->set_config = video_buffer_pool_set_config;
310   gstbufferpool_class->alloc_buffer = video_buffer_pool_alloc;
311 }
312
313 static void
314 gst_video_buffer_pool_init (GstVideoBufferPool * pool)
315 {
316   pool->priv = GST_VIDEO_BUFFER_POOL_GET_PRIVATE (pool);
317 }
318
319 static void
320 gst_video_buffer_pool_finalize (GObject * object)
321 {
322   GstVideoBufferPool *pool = GST_VIDEO_BUFFER_POOL_CAST (object);
323   GstVideoBufferPoolPrivate *priv = pool->priv;
324
325   GST_LOG_OBJECT (pool, "finalize video buffer pool %p", pool);
326
327   if (priv->caps)
328     gst_caps_unref (priv->caps);
329
330   if (priv->allocator)
331     gst_allocator_ref (priv->allocator);
332
333   G_OBJECT_CLASS (gst_video_buffer_pool_parent_class)->finalize (object);
334 }