tagsetter: use G_DEFINE_INTERFACE_* macro
[platform/upstream/gstreamer.git] / gst / gsttagsetter.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * gsttagsetter.c: interface for tag setting on elements
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:gsttagsetter
24  * @short_description: Element interface that allows setting and retrieval
25  *                     of media metadata
26  *
27  * Element interface that allows setting of media metadata.
28  *
29  * Elements that support changing a stream's metadata will implement this
30  * interface. Examples of such elements are 'vorbisenc', 'theoraenc' and
31  * 'id3v2mux'.
32  * 
33  * If you just want to retrieve metadata in your application then all you
34  * need to do is watch for tag messages on your pipeline's bus. This
35  * interface is only for setting metadata, not for extracting it. To set tags
36  * from the application, find tagsetter elements and set tags using e.g.
37  * gst_tag_setter_merge_tags() or gst_tag_setter_add_tags(). Also consider
38  * setting the #GstTagMergeMode that is used for tag events that arrive at the
39  * tagsetter element (default mode is to keep existing tags).
40  * The application should do that before the element goes to %GST_STATE_PAUSED.
41  * 
42  * Elements implementing the #GstTagSetter interface often have to merge
43  * any tags received from upstream and the tags set by the application via
44  * the interface. This can be done like this:
45  *
46  * |[
47  * GstTagMergeMode merge_mode;
48  * const GstTagList *application_tags;
49  * const GstTagList *event_tags;
50  * GstTagSetter *tagsetter;
51  * GstTagList *result;
52  *  
53  * tagsetter = GST_TAG_SETTER (element);
54  *  
55  * merge_mode = gst_tag_setter_get_tag_merge_mode (tagsetter);
56  * application_tags = gst_tag_setter_get_tag_list (tagsetter);
57  * event_tags = (const GstTagList *) element->event_tags;
58  *  
59  * GST_LOG_OBJECT (tagsetter, "merging tags, merge mode = %d", merge_mode);
60  * GST_LOG_OBJECT (tagsetter, "event tags: %" GST_PTR_FORMAT, event_tags);
61  * GST_LOG_OBJECT (tagsetter, "set   tags: %" GST_PTR_FORMAT, application_tags);
62  *  
63  * result = gst_tag_list_merge (application_tags, event_tags, merge_mode);
64  *  
65  * GST_LOG_OBJECT (tagsetter, "final tags: %" GST_PTR_FORMAT, result);
66  * ]|
67  * 
68  * Last reviewed on 2006-05-18 (0.10.6)
69  */
70
71 #ifdef HAVE_CONFIG_H
72 #  include "config.h"
73 #endif
74
75 #include "gst_private.h"
76 #include "gsttagsetter.h"
77 #include <gobject/gvaluecollector.h>
78 #include <string.h>
79
80 static GQuark gst_tag_key;
81
82 typedef struct
83 {
84   GstTagMergeMode mode;
85   GstTagList *list;
86   GMutex lock;
87 } GstTagData;
88
89 #define GST_TAG_DATA_LOCK(data) g_mutex_lock(&data->lock)
90 #define GST_TAG_DATA_UNLOCK(data) g_mutex_unlock(&data->lock)
91
92 G_DEFINE_INTERFACE_WITH_CODE (GstTagSetter, gst_tag_setter, GST_TYPE_ELEMENT,
93     gst_tag_key = g_quark_from_static_string ("gst-tag-setter-data");
94     );
95
96 static void
97 gst_tag_setter_default_init (GstTagSetterInterface * klass)
98 {
99   /* nothing to do here, it's a dummy interface */
100 }
101
102 static void
103 gst_tag_data_free (gpointer p)
104 {
105   GstTagData *data = (GstTagData *) p;
106
107   if (data->list)
108     gst_tag_list_unref (data->list);
109
110   g_mutex_clear (&data->lock);
111
112   g_slice_free (GstTagData, data);
113 }
114
115 static GstTagData *
116 gst_tag_setter_get_data (GstTagSetter * setter)
117 {
118   GstTagData *data;
119
120   data = g_object_get_qdata (G_OBJECT (setter), gst_tag_key);
121   if (!data) {
122     /* make sure no other thread is creating a GstTagData at the same time */
123     static GMutex create_mutex; /* no initialisation required */
124
125     g_mutex_lock (&create_mutex);
126
127     data = g_object_get_qdata (G_OBJECT (setter), gst_tag_key);
128     if (!data) {
129       data = g_slice_new (GstTagData);
130       g_mutex_init (&data->lock);
131       data->list = NULL;
132       data->mode = GST_TAG_MERGE_KEEP;
133       g_object_set_qdata_full (G_OBJECT (setter), gst_tag_key, data,
134           gst_tag_data_free);
135     }
136
137     g_mutex_unlock (&create_mutex);
138   }
139
140   return data;
141 }
142
143 /**
144  * gst_tag_setter_reset_tags:
145  * @setter: a #GstTagSetter
146  *
147  * Reset the internal taglist. Elements should call this from within the
148  * state-change handler.
149  *
150  * Since: 0.10.22
151  */
152 void
153 gst_tag_setter_reset_tags (GstTagSetter * setter)
154 {
155   GstTagData *data;
156
157   g_return_if_fail (GST_IS_TAG_SETTER (setter));
158
159   data = gst_tag_setter_get_data (setter);
160
161   GST_TAG_DATA_LOCK (data);
162   if (data->list) {
163     gst_tag_list_unref (data->list);
164     data->list = NULL;
165   }
166   GST_TAG_DATA_UNLOCK (data);
167 }
168
169 /**
170  * gst_tag_setter_merge_tags:
171  * @setter: a #GstTagSetter
172  * @list: a tag list to merge from
173  * @mode: the mode to merge with
174  *
175  * Merges the given list into the setter's list using the given mode.
176  */
177 void
178 gst_tag_setter_merge_tags (GstTagSetter * setter, const GstTagList * list,
179     GstTagMergeMode mode)
180 {
181   GstTagData *data;
182
183   g_return_if_fail (GST_IS_TAG_SETTER (setter));
184   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
185   g_return_if_fail (GST_IS_TAG_LIST (list));
186
187   data = gst_tag_setter_get_data (setter);
188
189   GST_TAG_DATA_LOCK (data);
190   if (data->list == NULL) {
191     if (mode != GST_TAG_MERGE_KEEP_ALL)
192       data->list = gst_tag_list_copy (list);
193   } else {
194     gst_tag_list_insert (data->list, list, mode);
195   }
196   GST_TAG_DATA_UNLOCK (data);
197 }
198
199 /**
200  * gst_tag_setter_add_tags:
201  * @setter: a #GstTagSetter
202  * @mode: the mode to use
203  * @tag: tag to set
204  * @...: more tag / value pairs to set
205  *
206  * Adds the given tag / value pairs on the setter using the given merge mode.
207  * The list must be terminated with NULL.
208  */
209 void
210 gst_tag_setter_add_tags (GstTagSetter * setter, GstTagMergeMode mode,
211     const gchar * tag, ...)
212 {
213   va_list args;
214
215   g_return_if_fail (GST_IS_TAG_SETTER (setter));
216   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
217
218   va_start (args, tag);
219   gst_tag_setter_add_tag_valist (setter, mode, tag, args);
220   va_end (args);
221 }
222
223 /**
224  * gst_tag_setter_add_tag_values:
225  * @setter: a #GstTagSetter
226  * @mode: the mode to use
227  * @tag: tag to set
228  * @...: more tag / GValue pairs to set
229  *
230  * Adds the given tag / GValue pairs on the setter using the given merge mode.
231  * The list must be terminated with NULL.
232  */
233 void
234 gst_tag_setter_add_tag_values (GstTagSetter * setter, GstTagMergeMode mode,
235     const gchar * tag, ...)
236 {
237   va_list args;
238
239   g_return_if_fail (GST_IS_TAG_SETTER (setter));
240   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
241
242   va_start (args, tag);
243   gst_tag_setter_add_tag_valist_values (setter, mode, tag, args);
244   va_end (args);
245 }
246
247 /**
248  * gst_tag_setter_add_tag_valist:
249  * @setter: a #GstTagSetter
250  * @mode: the mode to use
251  * @tag: tag to set
252  * @var_args: tag / value pairs to set
253  *
254  * Adds the given tag / value pairs on the setter using the given merge mode.
255  * The list must be terminated with NULL.
256  */
257 void
258 gst_tag_setter_add_tag_valist (GstTagSetter * setter, GstTagMergeMode mode,
259     const gchar * tag, va_list var_args)
260 {
261   GstTagData *data;
262
263   g_return_if_fail (GST_IS_TAG_SETTER (setter));
264   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
265
266   data = gst_tag_setter_get_data (setter);
267
268   GST_TAG_DATA_LOCK (data);
269   if (!data->list)
270     data->list = gst_tag_list_new_empty ();
271
272   gst_tag_list_add_valist (data->list, mode, tag, var_args);
273
274   GST_TAG_DATA_UNLOCK (data);
275 }
276
277 /**
278  * gst_tag_setter_add_tag_valist_values:
279  * @setter: a #GstTagSetter
280  * @mode: the mode to use
281  * @tag: tag to set
282  * @var_args: tag / GValue pairs to set
283  *
284  * Adds the given tag / GValue pairs on the setter using the given merge mode.
285  * The list must be terminated with NULL.
286  */
287 void
288 gst_tag_setter_add_tag_valist_values (GstTagSetter * setter,
289     GstTagMergeMode mode, const gchar * tag, va_list var_args)
290 {
291   GstTagData *data;
292
293   g_return_if_fail (GST_IS_TAG_SETTER (setter));
294   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
295
296   data = gst_tag_setter_get_data (setter);
297
298   GST_TAG_DATA_LOCK (data);
299
300   if (!data->list)
301     data->list = gst_tag_list_new_empty ();
302
303   gst_tag_list_add_valist_values (data->list, mode, tag, var_args);
304
305   GST_TAG_DATA_UNLOCK (data);
306 }
307
308 /**
309  * gst_tag_setter_add_tag_value:
310  * @setter: a #GstTagSetter
311  * @mode: the mode to use
312  * @tag: tag to set
313  * @value: GValue to set for the tag
314  *
315  * Adds the given tag / GValue pair on the setter using the given merge mode.
316  *
317  * Since: 0.10.24
318  */
319 void
320 gst_tag_setter_add_tag_value (GstTagSetter * setter,
321     GstTagMergeMode mode, const gchar * tag, const GValue * value)
322 {
323   GstTagData *data;
324
325   g_return_if_fail (GST_IS_TAG_SETTER (setter));
326   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
327
328   data = gst_tag_setter_get_data (setter);
329
330   GST_TAG_DATA_LOCK (data);
331
332   if (!data->list)
333     data->list = gst_tag_list_new_empty ();
334
335   gst_tag_list_add_value (data->list, mode, tag, value);
336
337   GST_TAG_DATA_UNLOCK (data);
338 }
339
340 /**
341  * gst_tag_setter_get_tag_list:
342  * @setter: a #GstTagSetter
343  *
344  * Returns the current list of tags the setter uses.  The list should not be
345  * modified or freed.
346  *
347  * This function is not thread-safe.
348  *
349  * Returns: (transfer none): a current snapshot of the taglist used in the
350  *          setter or NULL if none is used.
351  */
352 const GstTagList *
353 gst_tag_setter_get_tag_list (GstTagSetter * setter)
354 {
355   g_return_val_if_fail (GST_IS_TAG_SETTER (setter), NULL);
356
357   return gst_tag_setter_get_data (setter)->list;
358 }
359
360 /**
361  * gst_tag_setter_set_tag_merge_mode:
362  * @setter: a #GstTagSetter
363  * @mode: The mode with which tags are added
364  *
365  * Sets the given merge mode that is used for adding tags from events to tags
366  * specified by this interface. The default is #GST_TAG_MERGE_KEEP, which keeps
367  * the tags set with this interface and discards tags from events.
368  */
369 void
370 gst_tag_setter_set_tag_merge_mode (GstTagSetter * setter, GstTagMergeMode mode)
371 {
372   GstTagData *data;
373
374   g_return_if_fail (GST_IS_TAG_SETTER (setter));
375   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
376
377   data = gst_tag_setter_get_data (setter);
378
379   GST_TAG_DATA_LOCK (data);
380   data->mode = mode;
381   GST_TAG_DATA_UNLOCK (data);
382 }
383
384 /**
385  * gst_tag_setter_get_tag_merge_mode:
386  * @setter: a #GstTagSetter
387  *
388  * Queries the mode by which tags inside the setter are overwritten by tags
389  * from events
390  *
391  * Returns: the merge mode used inside the element.
392  */
393 GstTagMergeMode
394 gst_tag_setter_get_tag_merge_mode (GstTagSetter * setter)
395 {
396   GstTagMergeMode mode;
397   GstTagData *data;
398
399   g_return_val_if_fail (GST_IS_TAG_SETTER (setter), GST_TAG_MERGE_UNDEFINED);
400
401   data = gst_tag_setter_get_data (setter);
402
403   GST_TAG_DATA_LOCK (data);
404   mode = data->mode;
405   GST_TAG_DATA_UNLOCK (data);
406
407   return mode;
408 }