taglist: Avoid assertions when getting tag nick from unregister tag
[platform/upstream/gstreamer.git] / gst / gststreams.c
1 /* GStreamer
2  *
3  * Copyright (C) 2015 Centricular Ltd
4  *  @author: Edward Hervey <edward@centricular.com>
5  *  @author: Jan Schmidt <jan@centricular.com>
6  *
7  * gststreams.c: GstStream and GstStreamCollection object and methods
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  * MT safe.
25  */
26
27 /**
28  * SECTION:gststreams
29  * @title: GstStreams
30  * @short_description: Base class for stream objects
31  *
32  * A #GstStream is a high-level object defining a stream of data which is, or
33  * can be, present in a #GstPipeline.
34  *
35  * It is defined by a unique identifier, a "Stream ID". A #GstStream does not
36  * automatically imply the stream is present within a pipeline or element.
37  *
38  * Any element that can introduce new streams in a pipeline should create the
39  * appropriate #GstStream object, and can convey that object via the
40  * %GST_EVENT_STREAM_START event and/or the #GstStreamCollection.
41  *
42  * Elements that do not modify the nature of the stream can add extra information
43  * on it (such as enrich the #GstCaps, or #GstTagList). This is typically done
44  * by parsing elements.
45  *
46  * Since: 1.10
47  */
48
49 #include "gst_private.h"
50
51 #include "gstenumtypes.h"
52 #include "gstevent.h"
53 #include "gststreams.h"
54
55 GST_DEBUG_CATEGORY_STATIC (streams_debug);
56 #define GST_CAT_DEFAULT streams_debug
57
58 #define GST_STREAM_GET_PRIVATE(obj)  \
59    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_STREAM, GstStreamPrivate))
60
61 struct _GstStreamPrivate
62 {
63   GstStreamFlags flags;
64   GstStreamType type;
65   GstTagList *tags;
66   GstCaps *caps;
67 };
68
69 /* stream signals and properties */
70 enum
71 {
72   LAST_SIGNAL
73 };
74
75 enum
76 {
77   PROP_0,
78   PROP_STREAM_ID,
79   PROP_STREAM_FLAGS,
80   PROP_STREAM_TYPE,
81   PROP_TAGS,
82   PROP_CAPS,
83   PROP_LAST
84 };
85
86 static GParamSpec *gst_stream_pspecs[PROP_LAST] = { 0 };
87
88 #if 0
89 static guint gst_stream_signals[LAST_SIGNAL] = { 0 };
90 #endif
91
92 static void gst_stream_finalize (GObject * object);
93
94 static void gst_stream_set_property (GObject * object, guint prop_id,
95     const GValue * value, GParamSpec * pspec);
96 static void gst_stream_get_property (GObject * object, guint prop_id,
97     GValue * value, GParamSpec * pspec);
98
99 #define _do_init                                \
100 { \
101   GST_DEBUG_CATEGORY_INIT (streams_debug, "streams", GST_DEBUG_BOLD, \
102       "debugging info for the stream and stream collection objects"); \
103   \
104 }
105
106 #define gst_stream_parent_class parent_class
107 G_DEFINE_TYPE_WITH_CODE (GstStream, gst_stream, GST_TYPE_OBJECT, _do_init);
108
109 static void
110 gst_stream_class_init (GstStreamClass * klass)
111 {
112   GObjectClass *gobject_class;
113
114   gobject_class = (GObjectClass *) klass;
115
116   g_type_class_add_private (klass, sizeof (GstStreamPrivate));
117
118   gobject_class->set_property = gst_stream_set_property;
119   gobject_class->get_property = gst_stream_get_property;
120
121   /**
122    * GstStream:stream-id:
123    *
124    * The unique identifier of the #GstStream. Can only be set at construction
125    * time.
126    */
127   g_object_class_install_property (gobject_class, PROP_STREAM_ID,
128       g_param_spec_string ("stream-id", "Stream ID",
129           "The stream ID of the stream",
130           NULL,
131           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
132
133   /**
134    * GstStream:flags:
135    *
136    * The #GstStreamFlags of the #GstStream. Can only be set at construction time.
137    **/
138   gst_stream_pspecs[PROP_STREAM_FLAGS] =
139       g_param_spec_flags ("stream-flags", "Stream Flags", "The stream flags",
140       GST_TYPE_STREAM_FLAGS, GST_STREAM_FLAG_NONE,
141       G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
142   g_object_class_install_property (gobject_class, PROP_STREAM_FLAGS,
143       gst_stream_pspecs[PROP_STREAM_FLAGS]);
144
145   /**
146    * GstStream:stream-type:
147    *
148    * The #GstStreamType of the #GstStream. Can only be set at construction time.
149    **/
150   gst_stream_pspecs[PROP_STREAM_TYPE] =
151       g_param_spec_flags ("stream-type", "Stream Type", "The type of stream",
152       GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN,
153       G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
154   g_object_class_install_property (gobject_class, PROP_STREAM_TYPE,
155       gst_stream_pspecs[PROP_STREAM_TYPE]);
156
157   /**
158    * GstStream:caps:
159    *
160    * The #GstCaps of the #GstStream.
161    **/
162   gst_stream_pspecs[PROP_CAPS] =
163       g_param_spec_boxed ("caps", "Caps", "The caps of the stream",
164       GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
165   g_object_class_install_property (gobject_class, PROP_CAPS,
166       gst_stream_pspecs[PROP_CAPS]);
167
168   /**
169    * GstStream:tags:
170    *
171    * The #GstTagList of the #GstStream.
172    **/
173   gst_stream_pspecs[PROP_TAGS] =
174       g_param_spec_boxed ("tags", "Tags", "The tags of the stream",
175       GST_TYPE_TAG_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
176   g_object_class_install_property (gobject_class, PROP_TAGS,
177       gst_stream_pspecs[PROP_TAGS]);
178
179   gobject_class->finalize = gst_stream_finalize;
180 }
181
182 static void
183 gst_stream_init (GstStream * stream)
184 {
185   stream->priv = GST_STREAM_GET_PRIVATE (stream);
186   stream->priv->type = GST_STREAM_TYPE_UNKNOWN;
187 }
188
189 static void
190 gst_stream_finalize (GObject * object)
191 {
192   GstStream *stream = GST_STREAM_CAST (object);
193
194   gst_mini_object_replace ((GstMiniObject **) & stream->priv->tags,
195       (GstMiniObject *) NULL);
196   gst_caps_replace (&stream->priv->caps, NULL);
197   g_free ((gchar *) stream->stream_id);
198
199   G_OBJECT_CLASS (parent_class)->finalize (object);
200 }
201
202 /**
203  * gst_stream_new:
204  * @stream_id: (allow-none): the id for the new stream. If %NULL,
205  * a new one will be automatically generated
206  * @caps: (allow-none) (transfer none): the #GstCaps of the stream
207  * @type: the #GstStreamType of the stream
208  * @flags: the #GstStreamFlags of the stream
209  *
210  * Create a new #GstStream for the given @stream_id, @caps, @type
211  * and @flags
212  *
213  * Returns: (transfer full): The new #GstStream
214  *
215  * Since: 1.10
216  */
217 GstStream *
218 gst_stream_new (const gchar * stream_id, GstCaps * caps, GstStreamType type,
219     GstStreamFlags flags)
220 {
221   GstStream *stream;
222
223   stream = g_object_new (GST_TYPE_STREAM, "stream-id", stream_id, "caps", caps,
224       "stream-type", type, "stream-flags", flags, NULL);
225
226   /* Clear floating flag */
227   gst_object_ref_sink (stream);
228
229   return stream;
230 }
231
232 static void
233 gst_stream_set_stream_id (GstStream * stream, const gchar * stream_id)
234 {
235   GST_OBJECT_LOCK (stream);
236   g_assert (stream->stream_id == NULL);
237   if (stream_id)
238     stream->stream_id = g_strdup (stream_id);
239   else {
240     /* Create a randoom stream_id if NULL */
241     GST_FIXME_OBJECT (stream, "Creating random stream-id, consider "
242         "implementing a deterministic way of creating a stream-id");
243     stream->stream_id =
244         g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
245         g_random_int (), g_random_int ());
246   }
247
248   GST_OBJECT_UNLOCK (stream);
249 }
250
251 /**
252  * gst_stream_get_stream_id:
253  * @stream: a #GstStream
254  *
255  * Returns the stream ID of @stream.
256  *
257  * Returns: (transfer none) (nullable): the stream ID of @stream. Only valid
258  * during the lifetime of @stream.
259  *
260  * Since: 1.10
261  */
262 const gchar *
263 gst_stream_get_stream_id (GstStream * stream)
264 {
265   return stream->stream_id;
266 }
267
268 /**
269  * gst_stream_set_stream_flags:
270  * @stream: a #GstStream
271  * @flags: the flags to set on @stream
272  *
273  * Set the @flags for the @stream.
274  *
275  * Since: 1.10
276  */
277 void
278 gst_stream_set_stream_flags (GstStream * stream, GstStreamFlags flags)
279 {
280   GST_OBJECT_LOCK (stream);
281   stream->priv->flags = flags;
282   GST_OBJECT_UNLOCK (stream);
283
284   g_object_notify_by_pspec (G_OBJECT (stream),
285       gst_stream_pspecs[PROP_STREAM_FLAGS]);
286 }
287
288 /**
289  * gst_stream_get_stream_flags:
290  * @stream: a #GstStream
291  *
292  * Retrieve the current stream flags for @stream
293  *
294  * Returns: The #GstStreamFlags for @stream
295  *
296  * Since: 1.10
297  */
298 GstStreamFlags
299 gst_stream_get_stream_flags (GstStream * stream)
300 {
301   GstStreamFlags res;
302
303   GST_OBJECT_LOCK (stream);
304   res = stream->priv->flags;
305   GST_OBJECT_UNLOCK (stream);
306
307   return res;
308 }
309
310 /**
311  * gst_stream_set_stream_type:
312  * @stream: a #GstStream
313  * @stream_type: the type to set on @stream
314  *
315  * Set the stream type of @stream
316  *
317  * Since: 1.10
318  */
319 void
320 gst_stream_set_stream_type (GstStream * stream, GstStreamType stream_type)
321 {
322   GST_OBJECT_LOCK (stream);
323   stream->priv->type = stream_type;
324   GST_OBJECT_UNLOCK (stream);
325
326   g_object_notify_by_pspec (G_OBJECT (stream),
327       gst_stream_pspecs[PROP_STREAM_TYPE]);
328 }
329
330 /**
331  * gst_stream_get_stream_type:
332  * @stream: a #GstStream
333  *
334  * Retrieve the stream type for @stream
335  *
336  * Returns: The #GstStreamType for @stream
337  *
338  * Since: 1.10
339  */
340 GstStreamType
341 gst_stream_get_stream_type (GstStream * stream)
342 {
343   GstStreamType res;
344
345   GST_OBJECT_LOCK (stream);
346   res = stream->priv->type;
347   GST_OBJECT_UNLOCK (stream);
348
349   return res;
350 }
351
352 /**
353  * gst_stream_set_tags:
354  * @stream: a #GstStream
355  * @tags: (transfer none) (allow-none): a #GstTagList
356  *
357  * Set the tags for the #GstStream
358  *
359  * Since: 1.10
360  */
361 void
362 gst_stream_set_tags (GstStream * stream, GstTagList * tags)
363 {
364   gboolean notify = FALSE;
365
366   GST_OBJECT_LOCK (stream);
367   if (stream->priv->tags == NULL || tags == NULL
368       || !gst_tag_list_is_equal (stream->priv->tags, tags)) {
369     gst_mini_object_replace ((GstMiniObject **) & stream->priv->tags,
370         (GstMiniObject *) tags);
371     notify = TRUE;
372   }
373   GST_OBJECT_UNLOCK (stream);
374
375   if (notify)
376     g_object_notify_by_pspec (G_OBJECT (stream), gst_stream_pspecs[PROP_TAGS]);
377 }
378
379 /**
380  * gst_stream_get_tags:
381  * @stream: a #GstStream
382  *
383  * Retrieve the tags for @stream, if any
384  *
385  * Returns: (transfer full) (nullable): The #GstTagList for @stream
386  *
387  * Since: 1.10
388  */
389 GstTagList *
390 gst_stream_get_tags (GstStream * stream)
391 {
392   GstTagList *res = NULL;
393
394   GST_OBJECT_LOCK (stream);
395   if (stream->priv->tags)
396     res = gst_tag_list_ref (stream->priv->tags);
397   GST_OBJECT_UNLOCK (stream);
398
399   return res;
400 }
401
402 /**
403  * gst_stream_set_caps:
404  * @stream: a #GstStream
405  * @caps: (transfer none) (allow-none): a #GstCaps
406  *
407  * Set the caps for the #GstStream
408  *
409  * Since: 1.10
410  */
411 void
412 gst_stream_set_caps (GstStream * stream, GstCaps * caps)
413 {
414   gboolean notify = FALSE;
415
416   GST_OBJECT_LOCK (stream);
417   if (stream->priv->caps == NULL || (caps
418           && !gst_caps_is_equal (stream->priv->caps, caps))) {
419     gst_caps_replace (&stream->priv->caps, caps);
420     notify = TRUE;
421   }
422   GST_OBJECT_UNLOCK (stream);
423
424   if (notify)
425     g_object_notify_by_pspec (G_OBJECT (stream), gst_stream_pspecs[PROP_CAPS]);
426 }
427
428
429 /**
430  * gst_stream_get_caps:
431  * @stream: a #GstStream
432  *
433  * Retrieve the caps for @stream, if any
434  *
435  * Returns: (transfer full) (nullable): The #GstCaps for @stream
436  *
437  * Since: 1.10
438  */
439 GstCaps *
440 gst_stream_get_caps (GstStream * stream)
441 {
442   GstCaps *res = NULL;
443
444   GST_OBJECT_LOCK (stream);
445   if (stream->priv->caps)
446     res = gst_caps_ref (stream->priv->caps);
447   GST_OBJECT_UNLOCK (stream);
448
449   return res;
450 }
451
452 static void
453 gst_stream_set_property (GObject * object, guint prop_id,
454     const GValue * value, GParamSpec * pspec)
455 {
456   GstStream *stream;
457
458   stream = GST_STREAM_CAST (object);
459
460   switch (prop_id) {
461     case PROP_STREAM_ID:
462       gst_stream_set_stream_id (stream, g_value_get_string (value));
463       break;
464     case PROP_STREAM_FLAGS:
465       GST_OBJECT_LOCK (stream);
466       stream->priv->flags = g_value_get_flags (value);
467       GST_OBJECT_UNLOCK (stream);
468       break;
469     case PROP_STREAM_TYPE:
470       GST_OBJECT_LOCK (stream);
471       stream->priv->type = g_value_get_flags (value);
472       GST_OBJECT_UNLOCK (stream);
473       break;
474     case PROP_TAGS:
475       GST_OBJECT_LOCK (stream);
476       gst_mini_object_replace ((GstMiniObject **) & stream->priv->tags,
477           (GstMiniObject *) g_value_get_boxed (value));
478       GST_OBJECT_UNLOCK (stream);
479       break;
480     case PROP_CAPS:
481       GST_OBJECT_LOCK (stream);
482       gst_mini_object_replace ((GstMiniObject **) & stream->priv->caps,
483           (GstMiniObject *) g_value_get_boxed (value));
484       GST_OBJECT_UNLOCK (stream);
485       break;
486     default:
487       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
488       break;
489   }
490 }
491
492 static void
493 gst_stream_get_property (GObject * object, guint prop_id,
494     GValue * value, GParamSpec * pspec)
495 {
496   GstStream *stream;
497
498   stream = GST_STREAM_CAST (object);
499
500   switch (prop_id) {
501     case PROP_STREAM_ID:
502       g_value_set_string (value, gst_stream_get_stream_id (stream));
503       break;
504     case PROP_STREAM_FLAGS:
505       g_value_set_flags (value, gst_stream_get_stream_flags (stream));
506       break;
507     case PROP_STREAM_TYPE:
508       g_value_set_flags (value, gst_stream_get_stream_type (stream));
509       break;
510     case PROP_TAGS:
511       g_value_take_boxed (value, gst_stream_get_tags (stream));
512       break;
513     case PROP_CAPS:
514       g_value_take_boxed (value, gst_stream_get_caps (stream));
515       break;
516     default:
517       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
518       break;
519   }
520 }
521
522 /**
523  * gst_stream_type_get_name:
524  * @stype: a #GstStreamType
525  *
526  * Get a descriptive string for a given #GstStreamType
527  *
528  * Returns: A string describing the stream type
529  *
530  * Since: 1.10
531  */
532 const gchar *
533 gst_stream_type_get_name (GstStreamType stype)
534 {
535   /* FIXME : Make this more flexible */
536   switch (stype) {
537     case GST_STREAM_TYPE_UNKNOWN:
538       return "unknown";
539     case GST_STREAM_TYPE_AUDIO:
540       return "audio";
541     case GST_STREAM_TYPE_VIDEO:
542       return "video";
543     case GST_STREAM_TYPE_CONTAINER:
544       return "container";
545     case GST_STREAM_TYPE_TEXT:
546       return "text";
547     default:
548       return NULL;
549   }
550
551   return NULL;
552 }