8684dea2822c6d2f1763313e348c3121c0e4dfb5
[platform/upstream/gstreamer.git] / gst-libs / gst / video / gstvideometa.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 "gstvideometa.h"
21
22 static void
23 gst_video_meta_copy (GstBuffer * dest, GstMeta * meta,
24     GstBuffer * buffer, gsize offset, gsize size)
25 {
26   GstVideoMeta *dmeta, *smeta;
27   guint i;
28
29   smeta = (GstVideoMeta *) meta;
30
31   dmeta =
32       (GstVideoMeta *) gst_buffer_add_meta (dest, GST_VIDEO_META_INFO, NULL);
33   dmeta->buffer = dest;
34
35   dmeta->flags = smeta->flags;
36   dmeta->id = smeta->id;
37   dmeta->format = smeta->format;
38   dmeta->width = smeta->width;
39   dmeta->height = smeta->height;
40
41   dmeta->n_planes = smeta->n_planes;
42   for (i = 0; i < dmeta->n_planes; i++) {
43     dmeta->offset[i] = smeta->offset[i];
44     dmeta->stride[i] = smeta->stride[i];
45   }
46 }
47
48 /* video metadata */
49 const GstMetaInfo *
50 gst_video_meta_get_info (void)
51 {
52   static const GstMetaInfo *video_meta_info = NULL;
53
54   if (video_meta_info == NULL) {
55     video_meta_info = gst_meta_register (GST_VIDEO_META_API, "GstVideoMeta",
56         sizeof (GstVideoMeta),
57         (GstMetaInitFunction) NULL,
58         (GstMetaFreeFunction) NULL,
59         gst_video_meta_copy, (GstMetaTransformFunction) NULL);
60   }
61   return video_meta_info;
62 }
63
64 /**
65  * gst_buffer_get_video_meta_id:
66  * @buffer: a #GstBuffer
67  * @id: a metadata id
68  *
69  * Find the #GstVideoMeta on @buffer with the given @id.
70  *
71  * Buffers can contain multiple #GstVideoMeta metadata items when dealing with
72  * multiview buffers.
73  *
74  * Returns: the #GstVideoMeta with @id or %NULL when there is no such metadata
75  * on @buffer.
76  */
77 GstVideoMeta *
78 gst_buffer_get_video_meta_id (GstBuffer * buffer, gint id)
79 {
80   gpointer state = NULL;
81   GstMeta *meta;
82   const GstMetaInfo *info = GST_VIDEO_META_INFO;
83
84   while ((meta = gst_buffer_iterate_meta (buffer, &state))) {
85     if (meta->info->api == info->api) {
86       GstVideoMeta *vmeta = (GstVideoMeta *) meta;
87       if (vmeta->id == id)
88         return vmeta;
89     }
90   }
91   return NULL;
92 }
93
94 static gboolean
95 default_map (GstVideoMeta * meta, guint plane, GstMapInfo * info,
96     gpointer * data, gint * stride, GstMapFlags flags)
97 {
98   guint n, i;
99   guint offset;
100   GstBuffer *buffer = meta->buffer;
101
102   if ((n = gst_buffer_n_memory (buffer)) == 0)
103     goto no_memory;
104
105   offset = meta->offset[plane];
106   *stride = meta->stride[plane];
107   /* find the memory block for this plane, this is the memory block containing
108    * the plane offset. @offset will be updated with the offset inside the memory
109    * block where the plane starts. */
110   for (i = 0; i < n; i++) {
111     GstMemory *mem = NULL;
112     gsize size;
113
114     mem = gst_buffer_get_memory (buffer, i);
115     size = gst_memory_get_sizes (mem, NULL, NULL);
116
117     if (offset < size) {
118       GstMemory *mapped;
119
120       if (!(mapped = gst_memory_make_mapped (mem, info, flags)))
121         goto cannot_map;
122
123       /* buffer is writable when WRITE map is requested, we checked this in
124        * _map * */
125       if (mapped != mem && (flags & GST_MAP_WRITE))
126         gst_buffer_replace_memory (buffer, i, gst_memory_ref (mapped));
127
128       *data = (guint8 *) info->data + offset;
129       return TRUE;
130     }
131     offset -= size;
132     gst_memory_unref (mem);
133   }
134   GST_DEBUG ("no memory found for offset %u", meta->offset[plane]);
135   return FALSE;
136
137   /* ERRORS */
138 no_memory:
139   {
140     GST_DEBUG ("no memory");
141     return FALSE;
142   }
143 cannot_map:
144   {
145     GST_DEBUG ("cannot map memory");
146     return FALSE;
147   }
148 }
149
150 static gboolean
151 default_unmap (GstVideoMeta * meta, guint plane, GstMapInfo * info)
152 {
153   gst_memory_unmap (info->memory, info);
154   gst_memory_unref (info->memory);
155
156   return TRUE;
157 }
158
159 /**
160  * gst_buffer_add_video_meta:
161  * @buffer: a #GstBuffer
162  * @flags: #GstVideoFlags
163  * @format: a #GstVideoFormat
164  * @width: the width
165  * @height: the height
166  *
167  * Attaches GstVideoMeta metadata to @buffer with the given parameters and the
168  * default offsets and strides for @format and @width x @height.
169  *
170  * This function calculates the default offsets and strides and then calls
171  * gst_buffer_add_video_meta_full() with them.
172  *
173  * Returns: the #GstVideoMeta on @buffer.
174  */
175 GstVideoMeta *
176 gst_buffer_add_video_meta (GstBuffer * buffer, GstVideoFlags flags,
177     GstVideoFormat format, guint width, guint height)
178 {
179   GstVideoMeta *meta;
180   GstVideoInfo info;
181
182   gst_video_info_set_format (&info, format, width, height);
183
184   meta = gst_buffer_add_video_meta_full (buffer, flags, format, width, height,
185       info.finfo->n_planes, info.offset, info.stride);
186
187   return meta;
188 }
189
190 /**
191  * gst_buffer_add_video_meta_full:
192  * @buffer: a #GstBuffer
193  * @flags: #GstVideoFlags
194  * @format: a #GstVideoFormat
195  * @width: the width
196  * @height: the height
197  * @n_planes: number of planes
198  * @offset: offset of each plane
199  * @stride: stride of each plane
200  *
201  * Attaches GstVideoMeta metadata to @buffer with the given parameters.
202  *
203  * Returns: the #GstVideoMeta on @buffer.
204  */
205 GstVideoMeta *
206 gst_buffer_add_video_meta_full (GstBuffer * buffer, GstVideoFlags flags,
207     GstVideoFormat format, guint width, guint height,
208     guint n_planes, gsize offset[GST_VIDEO_MAX_PLANES],
209     gint stride[GST_VIDEO_MAX_PLANES])
210 {
211   GstVideoMeta *meta;
212   guint i;
213
214   meta =
215       (GstVideoMeta *) gst_buffer_add_meta (buffer, GST_VIDEO_META_INFO, NULL);
216
217   meta->flags = flags;
218   meta->format = format;
219   meta->id = 0;
220   meta->width = width;
221   meta->height = height;
222   meta->buffer = buffer;
223
224   meta->n_planes = n_planes;
225   for (i = 0; i < n_planes; i++) {
226     meta->offset[i] = offset[i];
227     meta->stride[i] = stride[i];
228   }
229   meta->map = default_map;
230   meta->unmap = default_unmap;
231
232   return meta;
233 }
234
235 /**
236  * gst_video_meta_map:
237  * @meta: a #GstVideoMeta
238  * @plane: a plane
239  * @info: a #GstMapInfo
240  * @data: the data of @plane
241  * @stride: the stride of @plane
242  * @flags: @GstMapFlags
243  *
244  * Map the video plane with index @plane in @meta and return a pointer to the
245  * first byte of the plane and the stride of the plane.
246  *
247  * Returns: TRUE if the map operation was successful.
248  */
249 gboolean
250 gst_video_meta_map (GstVideoMeta * meta, guint plane, GstMapInfo * info,
251     gpointer * data, gint * stride, GstMapFlags flags)
252 {
253   g_return_val_if_fail (meta != NULL, FALSE);
254   g_return_val_if_fail (meta->map != NULL, FALSE);
255   g_return_val_if_fail (plane < meta->n_planes, FALSE);
256   g_return_val_if_fail (info != NULL, FALSE);
257   g_return_val_if_fail (data != NULL, FALSE);
258   g_return_val_if_fail (stride != NULL, FALSE);
259   g_return_val_if_fail (meta->buffer != NULL, FALSE);
260   g_return_val_if_fail (!(flags & GST_MAP_WRITE)
261       || gst_buffer_is_writable (meta->buffer), FALSE);
262
263   return meta->map (meta, plane, info, data, stride, flags);
264 }
265
266 /**
267  * gst_video_meta_unmap:
268  * @meta: a #GstVideoMeta
269  * @plane: a plane
270  * @info: a #GstMapInfo
271  *
272  * Unmap a previously mapped plane with gst_video_meta_map().
273  *
274  * Returns: TRUE if the memory was successfully unmapped.
275  */
276 gboolean
277 gst_video_meta_unmap (GstVideoMeta * meta, guint plane, GstMapInfo * info)
278 {
279   g_return_val_if_fail (meta != NULL, FALSE);
280   g_return_val_if_fail (meta->unmap != NULL, FALSE);
281   g_return_val_if_fail (plane < meta->n_planes, FALSE);
282   g_return_val_if_fail (info != NULL, FALSE);
283
284   return meta->unmap (meta, plane, info);
285 }
286
287 static void
288 gst_video_crop_meta_copy (GstBuffer * dest, GstMeta * meta,
289     GstBuffer * buffer, gsize offset, gsize size)
290 {
291   GstVideoCropMeta *dmeta, *smeta;
292
293   smeta = (GstVideoCropMeta *) meta;
294   dmeta = gst_buffer_add_video_crop_meta (dest);
295
296   dmeta->x = smeta->x;
297   dmeta->y = smeta->y;
298   dmeta->width = smeta->width;
299   dmeta->height = smeta->height;
300 }
301
302 const GstMetaInfo *
303 gst_video_crop_meta_get_info (void)
304 {
305   static const GstMetaInfo *video_crop_meta_info = NULL;
306
307   if (video_crop_meta_info == NULL) {
308     video_crop_meta_info =
309         gst_meta_register (GST_VIDEO_CROP_META_API, "GstVideoCropMeta",
310         sizeof (GstVideoCropMeta), (GstMetaInitFunction) NULL,
311         (GstMetaFreeFunction) NULL, gst_video_crop_meta_copy,
312         (GstMetaTransformFunction) NULL);
313   }
314   return video_crop_meta_info;
315 }