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