| /* GStreamer |
| * |
| * Copyright (C) 2015 Centricular Ltd |
| * @author: Edward Hervey <edward@centricular.com> |
| * @author: Jan Schmidt <jan@centricular.com> |
| * |
| * gststreams.c: GstStreamCollection object and methods |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| * MT safe. |
| */ |
| |
| /** |
| * SECTION:gststreamcollection |
| * @title: GstStreamCollection |
| * @short_description: Base class for collection of streams |
| * |
| * Since: 1.10 |
| */ |
| |
| #include "gst_private.h" |
| |
| #include "gstenumtypes.h" |
| #include "gstevent.h" |
| #include "gststreamcollection.h" |
| |
| GST_DEBUG_CATEGORY_STATIC (stream_collection_debug); |
| #define GST_CAT_DEFAULT stream_collection_debug |
| |
| #define GST_STREAM_COLLECTION_GET_PRIVATE(obj) \ |
| (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_STREAM_COLLECTION, GstStreamCollectionPrivate)) |
| |
| struct _GstStreamCollectionPrivate |
| { |
| /* Maybe switch this to a GArray if performance is |
| * ever an issue? */ |
| GQueue *streams; |
| }; |
| |
| /* stream signals and properties */ |
| enum |
| { |
| SIG_STREAM_NOTIFY, |
| LAST_SIGNAL |
| }; |
| |
| enum |
| { |
| PROP_0, |
| PROP_UPSTREAM_ID, |
| PROP_LAST |
| }; |
| |
| static guint gst_stream_collection_signals[LAST_SIGNAL] = { 0 }; |
| |
| static void gst_stream_collection_dispose (GObject * object); |
| static void gst_stream_collection_finalize (GObject * object); |
| |
| static void gst_stream_collection_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec); |
| static void gst_stream_collection_get_property (GObject * object, guint prop_id, |
| GValue * value, GParamSpec * pspec); |
| |
| static void |
| proxy_stream_notify_cb (GstStream * stream, GParamSpec * pspec, |
| GstStreamCollection * collection); |
| |
| #define _do_init \ |
| { \ |
| GST_DEBUG_CATEGORY_INIT (stream_collection_debug, "streamcollection", GST_DEBUG_BOLD, \ |
| "debugging info for the stream collection objects"); \ |
| \ |
| } |
| |
| #define gst_stream_collection_parent_class parent_class |
| G_DEFINE_TYPE_WITH_CODE (GstStreamCollection, gst_stream_collection, |
| GST_TYPE_OBJECT, _do_init); |
| |
| static void |
| gst_stream_collection_class_init (GstStreamCollectionClass * klass) |
| { |
| GObjectClass *gobject_class; |
| |
| gobject_class = (GObjectClass *) klass; |
| |
| g_type_class_add_private (klass, sizeof (GstStreamCollectionPrivate)); |
| |
| gobject_class->set_property = gst_stream_collection_set_property; |
| gobject_class->get_property = gst_stream_collection_get_property; |
| |
| /** |
| * GstStream:upstream-id: |
| * |
| * stream-id |
| */ |
| g_object_class_install_property (gobject_class, PROP_UPSTREAM_ID, |
| g_param_spec_string ("upstream-id", "Upstream ID", |
| "The stream ID of the parent stream", |
| NULL, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); |
| |
| /** |
| * GstStream::stream-notify: |
| * @collection: a #GstStreamCollection |
| * @prop_stream: the #GstStream that originated the signal |
| * @prop: the property that changed |
| * |
| * The stream notify signal is used to be notified of property changes to |
| * streams within the collection. |
| */ |
| gst_stream_collection_signals[SIG_STREAM_NOTIFY] = |
| g_signal_new ("stream-notify", G_TYPE_FROM_CLASS (klass), |
| G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | |
| G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (GstStreamCollectionClass, |
| stream_notify), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, |
| 2, GST_TYPE_STREAM, G_TYPE_PARAM); |
| |
| gobject_class->dispose = gst_stream_collection_dispose; |
| gobject_class->finalize = gst_stream_collection_finalize; |
| } |
| |
| static void |
| gst_stream_collection_init (GstStreamCollection * collection) |
| { |
| collection->priv = GST_STREAM_COLLECTION_GET_PRIVATE (collection); |
| collection->priv->streams = g_queue_new (); |
| } |
| |
| static void |
| release_gst_stream (GstStream * stream, GstStreamCollection * collection) |
| { |
| g_signal_handlers_disconnect_by_func (stream, |
| proxy_stream_notify_cb, collection); |
| gst_object_unref (stream); |
| } |
| |
| static void |
| gst_stream_collection_dispose (GObject * object) |
| { |
| GstStreamCollection *collection = GST_STREAM_COLLECTION_CAST (object); |
| |
| if (collection->upstream_id) { |
| g_free (collection->upstream_id); |
| collection->upstream_id = NULL; |
| } |
| |
| if (collection->priv->streams) { |
| g_queue_foreach (collection->priv->streams, |
| (GFunc) release_gst_stream, collection); |
| g_queue_clear (collection->priv->streams); |
| } |
| |
| G_OBJECT_CLASS (parent_class)->dispose (object); |
| } |
| |
| static void |
| gst_stream_collection_finalize (GObject * object) |
| { |
| GstStreamCollection *collection = GST_STREAM_COLLECTION_CAST (object); |
| |
| if (collection->priv->streams) |
| g_queue_free (collection->priv->streams); |
| |
| G_OBJECT_CLASS (parent_class)->finalize (object); |
| } |
| |
| /** |
| * gst_stream_collection_new: |
| * @upstream_id: (allow-none): The stream id of the parent stream |
| * |
| * Create a new #GstStreamCollection. |
| * |
| * Returns: The new #GstStreamCollection. |
| * |
| * Since: 1.10 |
| */ |
| GstStreamCollection * |
| gst_stream_collection_new (const gchar * upstream_id) |
| { |
| return g_object_new (GST_TYPE_STREAM_COLLECTION, "upstream-id", upstream_id, |
| NULL); |
| } |
| |
| static void |
| gst_stream_collection_set_upstream_id (GstStreamCollection * collection, |
| const gchar * upstream_id) |
| { |
| g_return_if_fail (collection->upstream_id == NULL); |
| |
| /* Upstream ID should only be set once on construction, but let's |
| * not leak in case someone does something silly */ |
| if (collection->upstream_id) |
| g_free (collection->upstream_id); |
| |
| if (upstream_id) |
| collection->upstream_id = g_strdup (upstream_id); |
| } |
| |
| /** |
| * gst_stream_collection_get_upstream_id: |
| * @collection: a #GstStreamCollection |
| * |
| * Returns the upstream id of the @collection. |
| * |
| * Returns: (transfer none): The upstream id |
| * |
| * Since: 1.10 |
| */ |
| const gchar * |
| gst_stream_collection_get_upstream_id (GstStreamCollection * collection) |
| { |
| const gchar *res; |
| |
| res = collection->upstream_id; |
| |
| return res; |
| } |
| |
| static void |
| gst_stream_collection_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec) |
| { |
| GstStreamCollection *collection; |
| |
| collection = GST_STREAM_COLLECTION_CAST (object); |
| |
| switch (prop_id) { |
| case PROP_UPSTREAM_ID: |
| gst_stream_collection_set_upstream_id (collection, |
| g_value_get_string (value)); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_stream_collection_get_property (GObject * object, guint prop_id, |
| GValue * value, GParamSpec * pspec) |
| { |
| GstStreamCollection *collection; |
| |
| collection = GST_STREAM_COLLECTION_CAST (object); |
| |
| switch (prop_id) { |
| case PROP_UPSTREAM_ID: |
| g_value_set_string (value, |
| gst_stream_collection_get_upstream_id (collection)); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| proxy_stream_notify_cb (GstStream * stream, GParamSpec * pspec, |
| GstStreamCollection * collection) |
| { |
| GST_DEBUG_OBJECT (collection, "Stream %" GST_PTR_FORMAT " updated %s", |
| stream, pspec->name); |
| g_signal_emit (collection, gst_stream_collection_signals[SIG_STREAM_NOTIFY], |
| g_quark_from_string (pspec->name), stream, pspec); |
| } |
| |
| /** |
| * gst_stream_collection_add_stream: |
| * @collection: a #GstStreamCollection |
| * @stream: (transfer full): the #GstStream to add |
| * |
| * Add the given @stream to the @collection. |
| * |
| * Returns: %TRUE if the @stream was properly added, else %FALSE |
| * |
| * Since: 1.10 |
| */ |
| gboolean |
| gst_stream_collection_add_stream (GstStreamCollection * collection, |
| GstStream * stream) |
| { |
| g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), FALSE); |
| g_return_val_if_fail (GST_IS_STREAM (stream), FALSE); |
| g_return_val_if_fail (collection->priv->streams, FALSE); |
| |
| GST_DEBUG_OBJECT (collection, "Adding stream %" GST_PTR_FORMAT, stream); |
| |
| g_queue_push_tail (collection->priv->streams, stream); |
| g_signal_connect (stream, "notify", (GCallback) proxy_stream_notify_cb, |
| collection); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_stream_collection_get_size: |
| * @collection: a #GstStreamCollection |
| * |
| * Get the number of streams this collection contains |
| * |
| * Returns: The number of streams that @collection contains |
| * |
| * Since: 1.10 |
| */ |
| guint |
| gst_stream_collection_get_size (GstStreamCollection * collection) |
| { |
| g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), 0); |
| g_return_val_if_fail (collection->priv->streams, 0); |
| |
| return g_queue_get_length (collection->priv->streams); |
| } |
| |
| /** |
| * gst_stream_collection_get_stream: |
| * @collection: a #GstStreamCollection |
| * @index: Index of the stream to retrieve |
| * |
| * Retrieve the #GstStream with index @index from the collection. |
| * |
| * The caller should not modify the returned #GstStream |
| * |
| * Returns: (transfer none): A #GstStream |
| * |
| * Since: 1.10 |
| */ |
| GstStream * |
| gst_stream_collection_get_stream (GstStreamCollection * collection, guint index) |
| { |
| g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), NULL); |
| g_return_val_if_fail (collection->priv->streams, NULL); |
| |
| return g_queue_peek_nth (collection->priv->streams, index); |
| } |