meta: add timing metadata
[platform/upstream/gstreamer.git] / gst / gstmeta.c
1 /* GStreamer
2  * Copyright (C) 2011 Wim Taymans <wim.taymans@gmail.com>
3  *
4  * gstmeta.c: metadata operations
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstmeta
24  * @short_description: Buffer metadata
25  *
26  * Last reviewed on December 17th, 2009 (0.10.26)
27  */
28 #include "gst_private.h"
29
30 #include "gstbuffer.h"
31 #include "gstmeta.h"
32 #include "gstinfo.h"
33 #include "gstutils.h"
34
35 static GHashTable *metainfo = NULL;
36 static GStaticRWLock lock = G_STATIC_RW_LOCK_INIT;
37
38 void
39 _gst_meta_init (void)
40 {
41   metainfo = g_hash_table_new (g_str_hash, g_str_equal);
42 }
43
44 /**
45  * gst_meta_register_info:
46  * @info: a #GstMetaInfo
47  *
48  * Register a #GstMetaInfo. The same @info can be retrieved later with
49  * gst_meta_get_info() by using @impl as the key.
50  *
51  * Returns: a #GstMetaInfo that can be used to access metadata.
52  */
53
54 const GstMetaInfo *
55 gst_meta_register (const gchar * api, const gchar * impl, gsize size,
56     GstMetaInitFunction init_func, GstMetaFreeFunction free_func,
57     GstMetaCopyFunction copy_func, GstMetaSubFunction sub_func,
58     GstMetaSerializeFunction serialize_func,
59     GstMetaDeserializeFunction deserialize_func)
60 {
61   GstMetaInfo *info;
62
63   g_return_val_if_fail (api != NULL, NULL);
64   g_return_val_if_fail (impl != NULL, NULL);
65   g_return_val_if_fail (size != 0, NULL);
66
67   info = g_slice_new (GstMetaInfo);
68   info->api = g_quark_from_string (api);
69   info->impl = g_quark_from_string (impl);
70   info->size = size;
71   info->init_func = init_func;
72   info->free_func = free_func;
73   info->copy_func = copy_func;
74   info->sub_func = sub_func;
75   info->serialize_func = serialize_func;
76   info->deserialize_func = deserialize_func;
77
78   GST_DEBUG ("register \"%s\" implementing \"%s\" of size %" G_GSIZE_FORMAT,
79       api, impl, size);
80
81   g_static_rw_lock_writer_lock (&lock);
82   g_hash_table_insert (metainfo, (gpointer) impl, (gpointer) info);
83   g_static_rw_lock_writer_unlock (&lock);
84
85   return info;
86 }
87
88 /**
89  * gst_meta_get_info:
90  * @name: the name
91  *
92  * Lookup a previously registered meta info structure by its @implementor name.
93  *
94  * Returns: a #GstMetaInfo with @name or #NULL when no such metainfo
95  * exists.
96  */
97 const GstMetaInfo *
98 gst_meta_get_info (const gchar * impl)
99 {
100   GstMetaInfo *info;
101
102   g_return_val_if_fail (impl != NULL, NULL);
103
104   g_static_rw_lock_reader_lock (&lock);
105   info = g_hash_table_lookup (metainfo, impl);
106   g_static_rw_lock_reader_unlock (&lock);
107
108   return info;
109 }
110
111 /* Memory metadata */
112 typedef struct
113 {
114   guint8 *data;
115   GFreeFunc free_func;
116   gsize size;
117   gsize offset;
118 } GstMetaMemoryParams;
119
120 typedef struct
121 {
122   GstMetaMemory memory;
123   GstMetaMemoryParams params;
124 } GstMetaMemoryImpl;
125
126 static gpointer
127 meta_memory_mmap (GstMetaMemory * meta, gsize offset, gsize * size,
128     GstMetaMapFlags flags)
129 {
130   GstMetaMemoryImpl *impl = (GstMetaMemoryImpl *) meta;
131
132   *size = impl->params.size - offset;
133   return impl->params.data + offset;
134 }
135
136 static gboolean
137 meta_memory_munmap (GstMetaMemory * meta, gpointer data, gsize size)
138 {
139   return TRUE;
140 }
141
142 static gboolean
143 meta_memory_init (GstMetaMemoryImpl * meta, GstMetaMemoryParams * params,
144     GstBuffer * buffer)
145 {
146   meta->memory.mmap_func = meta_memory_mmap;
147   meta->memory.munmap_func = meta_memory_munmap;
148   meta->params = *params;
149   return TRUE;
150 }
151
152 static void
153 meta_memory_free (GstMetaMemoryImpl * meta, GstBuffer * buffer)
154 {
155   if (meta->params.free_func)
156     meta->params.free_func (meta->params.data);
157 }
158
159 static void
160 meta_memory_copy (GstBuffer * copy, GstMetaMemoryImpl * meta,
161     const GstBuffer * buffer)
162 {
163   gst_buffer_add_meta_memory (copy,
164       g_memdup (meta->params.data, meta->params.size),
165       g_free, meta->params.size, meta->params.offset);
166 }
167
168 static void
169 meta_memory_sub (GstBuffer * subbuf, GstMetaMemoryImpl * meta,
170     GstBuffer * buffer, guint offset, guint size)
171 {
172   gst_buffer_add_meta_memory (subbuf,
173       meta->params.data, NULL, size, meta->params.offset + offset);
174 }
175
176 const GstMetaInfo *
177 gst_meta_memory_get_info (void)
178 {
179   static const GstMetaInfo *meta_info = NULL;
180
181   if (meta_info == NULL) {
182     meta_info = gst_meta_register ("GstMetaMemory", "GstMetaMemoryImpl",
183         sizeof (GstMetaMemoryImpl),
184         (GstMetaInitFunction) meta_memory_init,
185         (GstMetaFreeFunction) meta_memory_free,
186         (GstMetaCopyFunction) meta_memory_copy,
187         (GstMetaSubFunction) meta_memory_sub,
188         (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL);
189   }
190   return meta_info;
191 }
192
193 GstMetaMemory *
194 gst_buffer_add_meta_memory (GstBuffer * buffer, gpointer data,
195     GFreeFunc free_func, gsize size, gsize offset)
196 {
197   GstMeta *meta;
198   GstMetaMemoryParams params;
199
200   params.data = data;
201   params.free_func = free_func;
202   params.size = size;
203   params.offset = offset;
204
205   meta = gst_buffer_add_meta (buffer, GST_META_MEMORY_INFO, &params);
206
207   return (GstMetaMemory *) meta;
208 }
209
210 /* Timing metadata */
211 static void
212 meta_timing_copy (GstBuffer * copy, GstMetaTiming * meta, GstBuffer * buffer)
213 {
214   GstMetaTiming *timing;
215
216   GST_DEBUG ("copy called from buffer %p to %p, meta %p", buffer, copy, meta);
217
218   timing = gst_buffer_add_meta_timing (copy);
219   timing->pts = meta->pts;
220   timing->dts = meta->dts;
221   timing->duration = meta->duration;
222   timing->clock_rate = meta->clock_rate;
223 }
224
225 static void
226 meta_timing_sub (GstBuffer * sub, GstMetaTiming * meta, GstBuffer * buffer,
227     guint offset, guint size)
228 {
229   GstMetaTiming *timing;
230
231   GST_DEBUG ("sub called from buffer %p to %p, meta %p, %u-%u", buffer, sub,
232       meta, offset, size);
233
234   timing = gst_buffer_add_meta_timing (sub);
235   if (offset == 0) {
236     /* same offset, copy timestamps */
237     timing->pts = meta->pts;
238     timing->dts = meta->dts;
239     if (size == GST_BUFFER_SIZE (buffer)) {
240       /* same size, copy duration */
241       timing->duration = meta->duration;
242     } else {
243       /* else clear */
244       timing->duration = GST_CLOCK_TIME_NONE;
245     }
246   } else {
247     timing->pts = -1;
248     timing->dts = -1;
249     timing->duration = -1;
250   }
251   timing->clock_rate = meta->clock_rate;
252 }
253
254 const GstMetaInfo *
255 gst_meta_timing_get_info (void)
256 {
257   static const GstMetaInfo *meta_info = NULL;
258
259   if (meta_info == NULL) {
260     meta_info = gst_meta_register ("GstMetaTiming", "GstMetaTiming",
261         sizeof (GstMetaTiming),
262         (GstMetaInitFunction) NULL,
263         (GstMetaFreeFunction) NULL,
264         (GstMetaCopyFunction) meta_timing_copy,
265         (GstMetaSubFunction) meta_timing_sub,
266         (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL);
267   }
268   return meta_info;
269 }