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