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