d7e0dd18a72f982c3d97e99480333b39038cbf60
[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   const GstAllocator *allocator;
142   GstCaps *caps;
143   GstVideoInfo info;
144   GstVideoAlignment video_align;
145   gboolean add_metavideo;
146   gboolean need_alignment;
147   guint prefix;
148   guint align;
149 };
150
151 static void gst_video_buffer_pool_finalize (GObject * object);
152
153 #define GST_VIDEO_BUFFER_POOL_GET_PRIVATE(obj)  \
154    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VIDEO_BUFFER_POOL, GstVideoBufferPoolPrivate))
155
156 #define gst_video_buffer_pool_parent_class parent_class
157 G_DEFINE_TYPE (GstVideoBufferPool, gst_video_buffer_pool, GST_TYPE_BUFFER_POOL);
158
159 static const gchar **
160 video_buffer_pool_get_options (GstBufferPool * pool)
161 {
162   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
163     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
164   };
165   return options;
166 }
167
168 static gboolean
169 video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
170 {
171   GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool);
172   GstVideoBufferPoolPrivate *priv = vpool->priv;
173   GstVideoInfo info;
174   const GstCaps *caps;
175   gint width, height;
176   guint prefix, align;
177
178   if (!gst_buffer_pool_config_get (config, &caps, NULL, NULL, NULL, &prefix,
179           &align))
180     goto wrong_config;
181
182   if (caps == NULL)
183     goto no_caps;
184
185   /* now parse the caps from the config */
186   if (!gst_video_info_from_caps (&info, caps))
187     goto wrong_caps;
188
189   width = info.width;
190   height = info.height;
191
192   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps);
193
194   if (priv->caps)
195     gst_caps_unref (priv->caps);
196   priv->caps = gst_caps_copy (caps);
197   priv->prefix = prefix;
198   priv->align = align;
199
200   /* enable metadata based on config of the pool */
201   priv->add_metavideo =
202       gst_buffer_pool_config_has_option (config,
203       GST_BUFFER_POOL_OPTION_VIDEO_META);
204
205   /* parse extra alignment info */
206   priv->need_alignment = gst_buffer_pool_config_has_option (config,
207       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
208
209   if (priv->need_alignment) {
210     /* get an apply the alignment to the info */
211     gst_buffer_pool_config_get_video_alignment (config, &priv->video_align);
212     gst_video_info_align (&info, &priv->video_align);
213
214     /* we need the video metadata too now */
215     priv->add_metavideo = TRUE;
216   }
217   priv->info = info;
218
219   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
220
221   /* ERRORS */
222 wrong_config:
223   {
224     GST_WARNING_OBJECT (pool, "invalid config");
225     return FALSE;
226   }
227 no_caps:
228   {
229     GST_WARNING_OBJECT (pool, "no caps in config");
230     return FALSE;
231   }
232 wrong_caps:
233   {
234     GST_WARNING_OBJECT (pool,
235         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
236     return FALSE;
237   }
238 }
239
240 static GstFlowReturn
241 video_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
242     GstBufferPoolParams * params)
243 {
244   GstVideoBufferPool *vpool = GST_VIDEO_BUFFER_POOL_CAST (pool);
245   GstVideoBufferPoolPrivate *priv = vpool->priv;
246   GstVideoInfo *info;
247   GstMemory *mem;
248
249   info = &priv->info;
250
251   GST_DEBUG_OBJECT (pool, "alloc %" G_GSIZE_FORMAT, info->size);
252
253   mem =
254       gst_allocator_alloc (priv->allocator, info->size + priv->prefix,
255       priv->align);
256   if (mem == NULL)
257     goto no_memory;
258
259   *buffer = gst_buffer_new ();
260   gst_memory_resize (mem, priv->prefix, info->size);
261   gst_buffer_take_memory (*buffer, -1, mem);
262
263   if (priv->add_metavideo) {
264     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
265
266     gst_buffer_add_video_meta_full (*buffer, 0, GST_VIDEO_INFO_FORMAT (info),
267         GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
268         GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride);
269   }
270
271   return GST_FLOW_OK;
272
273   /* ERROR */
274 no_memory:
275   {
276     GST_WARNING_OBJECT (pool, "can't create memory");
277     return GST_FLOW_ERROR;
278   }
279 }
280
281 /**
282  * gst_video_buffer_pool_new:
283  *
284  * Create a new bufferpool that can allocate video frames. This bufferpool
285  * supports all the video bufferpool options.
286  *
287  * Returns: a new #GstBufferPool to allocate video frames
288  */
289 GstBufferPool *
290 gst_video_buffer_pool_new ()
291 {
292   GstVideoBufferPool *pool;
293
294   pool = g_object_new (GST_TYPE_VIDEO_BUFFER_POOL, NULL);
295
296   GST_LOG_OBJECT (pool, "new video buffer pool %p", pool);
297
298   return GST_BUFFER_POOL_CAST (pool);
299 }
300
301 static void
302 gst_video_buffer_pool_class_init (GstVideoBufferPoolClass * klass)
303 {
304   GObjectClass *gobject_class = (GObjectClass *) klass;
305   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
306
307   g_type_class_add_private (klass, sizeof (GstVideoBufferPoolPrivate));
308
309   gobject_class->finalize = gst_video_buffer_pool_finalize;
310
311   gstbufferpool_class->get_options = video_buffer_pool_get_options;
312   gstbufferpool_class->set_config = video_buffer_pool_set_config;
313   gstbufferpool_class->alloc_buffer = video_buffer_pool_alloc;
314 }
315
316 static void
317 gst_video_buffer_pool_init (GstVideoBufferPool * pool)
318 {
319   pool->priv = GST_VIDEO_BUFFER_POOL_GET_PRIVATE (pool);
320 }
321
322 static void
323 gst_video_buffer_pool_finalize (GObject * object)
324 {
325   GstVideoBufferPool *pool = GST_VIDEO_BUFFER_POOL_CAST (object);
326   GstVideoBufferPoolPrivate *priv = pool->priv;
327
328   GST_LOG_OBJECT (pool, "finalize video buffer pool %p", pool);
329
330   if (priv->caps)
331     gst_caps_unref (priv->caps);
332
333   G_OBJECT_CLASS (gst_video_buffer_pool_parent_class)->finalize (object);
334 }
335
336 /**
337  * gst_video_buffer_pool_get_allocator:
338  * @pool: a #GstVideoBufferPool
339  *
340  * Get the allocator used by @pool to allocate the video memory.
341  *
342  * Returns: the allocator used for allocating video memory
343  */
344 const GstAllocator *
345 gst_video_buffer_pool_get_allocator (GstVideoBufferPool * pool)
346 {
347   g_return_val_if_fail (GST_IS_VIDEO_BUFFER_POOL (pool), NULL);
348
349   return pool->priv->allocator;
350 }
351
352 /**
353  * gst_video_buffer_pool_set_allocator:
354  * @pool: a #GstVideoBufferPool
355  * @allocator: a #GstAllocator
356  *
357  * Set the allocator used to allocate video memory in @pool. The allocator
358  * should only be changed by subclasses.
359  */
360 void
361 gst_video_buffer_pool_set_allocator (GstVideoBufferPool * pool,
362     const GstAllocator * allocator)
363 {
364   g_return_if_fail (GST_IS_VIDEO_BUFFER_POOL (pool));
365
366   pool->priv->allocator = allocator;
367 }