Commit 998cf7d5 authored by Wim Taymans's avatar Wim Taymans

Add shared properties to media and factory

Add the shared property to media.
Implement some simple caching in the factory depending on if the media is shared
or not.
parent 08209900
......@@ -20,11 +20,13 @@
#include "rtsp-media-factory.h"
#define DEFAULT_LAUNCH NULL
#define DEFAULT_SHARED FALSE
enum
{
PROP_0,
PROP_LAUNCH,
PROP_SHARED,
PROP_LAST
};
......@@ -34,8 +36,10 @@ static void gst_rtsp_media_factory_set_property (GObject *object, guint propid,
const GValue *value, GParamSpec *pspec);
static void gst_rtsp_media_factory_finalize (GObject * obj);
static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
static gchar * default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
static GstElement * default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
static GstRTSPMedia * default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
static void default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
......@@ -67,13 +71,26 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
g_param_spec_string ("launch", "Launch", "A launch description of the pipeline",
DEFAULT_LAUNCH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
klass->construct = default_construct;
g_object_class_install_property (gobject_class, PROP_SHARED,
g_param_spec_boolean ("shared", "Shared", "If media from this factory is shared",
DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
klass->gen_key = default_gen_key;
klass->get_element = default_get_element;
klass->construct = default_construct;
klass->configure = default_configure;
}
static void
gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
{
factory->launch = g_strdup (DEFAULT_LAUNCH);
factory->shared = DEFAULT_SHARED;
factory->lock = g_mutex_new ();
factory->medias_lock = g_mutex_new ();
factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
static void
......@@ -81,7 +98,10 @@ gst_rtsp_media_factory_finalize (GObject * obj)
{
GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
g_hash_table_unref (factory->medias);
g_mutex_free (factory->medias_lock);
g_free (factory->launch);
g_mutex_free (factory->lock);
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
}
......@@ -96,6 +116,9 @@ gst_rtsp_media_factory_get_property (GObject *object, guint propid,
case PROP_LAUNCH:
g_value_take_string (value, gst_rtsp_media_factory_get_launch (factory));
break;
case PROP_SHARED:
g_value_set_boolean (value, gst_rtsp_media_factory_is_shared (factory));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
......@@ -111,6 +134,9 @@ gst_rtsp_media_factory_set_property (GObject *object, guint propid,
case PROP_LAUNCH:
gst_rtsp_media_factory_set_launch (factory, g_value_get_string (value));
break;
case PROP_SHARED:
gst_rtsp_media_factory_set_shared (factory, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
......@@ -155,7 +181,10 @@ gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory, const gchar *la
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_return_if_fail (launch != NULL);
g_mutex_lock (factory->lock);
g_free (factory->launch);
factory->launch = g_strdup (launch);
g_mutex_unlock (factory->lock);
}
/**
......@@ -172,7 +201,51 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory)
{
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
g_mutex_lock (factory->lock);
result = g_strdup (factory->launch);
g_mutex_unlock (factory->lock);
return result;
}
/**
* gst_rtsp_media_factory_set_shared:
* @factory: a #GstRTSPMediaFactory
* @shared: the new value
*
* Configure if media created from this factory can be shared between clients.
*/
void
gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *factory,
gboolean shared)
{
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_mutex_lock (factory->lock);
factory->shared = shared;
g_mutex_unlock (factory->lock);
}
/**
* gst_rtsp_media_factory_is_shared:
* @factory: a #GstRTSPMediaFactory
*
* Get if media created from this factory can be shared between clients.
*
* Returns: %TRUE if the media will be shared between clients.
*/
gboolean
gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory)
{
gboolean result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
g_mutex_lock (factory->lock);
result = factory->shared;
g_mutex_unlock (factory->lock);
return result;
}
......@@ -195,19 +268,68 @@ gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory)
GstRTSPMedia *
gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
{
GstRTSPMedia *res;
gchar *key;
GstRTSPMedia *media;
GstRTSPMediaFactoryClass *klass;
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
if (klass->construct)
res = klass->construct (factory, url);
/* convert the url to a key for the hashtable. NULL return or a NULL function
* will not cache anything for this factory. */
if (klass->gen_key)
key = klass->gen_key (factory, url);
else
key = NULL;
g_mutex_lock (factory->medias_lock);
if (key) {
/* we have a key, see if we find a cached media */
media = g_hash_table_lookup (factory->medias, key);
if (media)
g_object_ref (media);
}
else
res = NULL;
media = NULL;
if (media == NULL) {
/* nothing cached found, try to create one */
if (klass->construct)
media = klass->construct (factory, url);
else
media = NULL;
if (media) {
/* configure the media */
if (klass->configure)
klass->configure (factory, media);
/* check if we can cache this media */
if (gst_rtsp_media_is_shared (media)) {
/* insert in the hashtable, takes ownership of the key */
g_object_ref (media);
g_hash_table_insert (factory->medias, key, media);
key = NULL;
}
}
}
g_mutex_unlock (factory->medias_lock);
if (key)
g_free (key);
g_message ("constructed media %p for url %s", res, url->abspath);
g_message ("constructed media %p for url %s", media, url->abspath);
return res;
return media;
}
static gchar *
default_gen_key (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
{
gchar *result;
result = gst_rtsp_url_get_request_uri (url);
return result;
}
static GstElement *
......@@ -216,6 +338,7 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
GstElement *element;
GError *error = NULL;
g_mutex_lock (factory->lock);
/* we need a parse syntax */
if (factory->launch == NULL)
goto no_launch;
......@@ -225,6 +348,8 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
if (element == NULL)
goto parse_error;
g_mutex_unlock (factory->lock);
if (error != NULL) {
/* a recoverable error was encountered */
g_warning ("recoverable parsing error: %s", error->message);
......@@ -235,11 +360,13 @@ default_get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
/* ERRORS */
no_launch:
{
g_mutex_unlock (factory->lock);
g_critical ("no launch line specified");
return NULL;
}
parse_error:
{
g_mutex_unlock (factory->lock);
g_critical ("could not parse launch syntax (%s): %s", factory->launch,
(error ? error->message : "unknown reason"));
if (error)
......@@ -248,6 +375,7 @@ parse_error:
}
}
static GstRTSPMedia *
default_construct (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
{
......@@ -313,3 +441,16 @@ no_element:
return NULL;
}
}
static void
default_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media)
{
gboolean shared;
/* configure the sharedness */
g_mutex_lock (factory->lock);
shared = factory->shared;
g_mutex_unlock (factory->lock);
gst_rtsp_media_set_shared (media, shared);
}
......@@ -42,8 +42,11 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass;
/**
* GstRTSPMediaFactory:
* @lock: mutex protecting the datastructure.
* @launch: the launch description
* @streams: the array of #GstRTSPMediaStream objects for this media.
* @shared: if media from this factory can be shared between clients
* @media_lock: mutex protecting the medias.
* @media: hashtable of shared media
*
* The definition and logic for constructing the pipeline for a media. The media
* can contain multiple streams like audio and video.
......@@ -51,39 +54,52 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass;
struct _GstRTSPMediaFactory {
GObject parent;
GMutex *lock;
gchar *launch;
gboolean shared;
GMutex *medias_lock;
GHashTable *medias;
};
/**
* GstRTSPMediaFactoryClass:
* @gen_key: convert @url to a key for caching media
* @get_element: Construct an return a #GstElement thast is a #GstBin containing
* the elements to use for the media. The bin should contain payloaders
* pay%d for each stream. The default implementation of this functions
* returns the bin created from the launch parameter.
* @construct: the vmethod that will be called when the factory has to create the
* #GstRTSPMedia for @url. The default implementation of this
* function calls get_element to retrieve an element and then looks for
* pay%d to create the streams.
* @configure: configure the media created with @construct. The default
* implementation will configure the 'shared' property of the media.
* @handle_message: Handle a bus message for @media created from @factory.
* @get_element: Construct an return a #GstElement thast is a #GstBin containing
* the pipeline to use for the media. The bin should contain elements
* pay%d for each stream. The default implementation of this functions
* returns the bin created from the launch parameter.
*
* the #GstRTSPMediaFactory class structure.
*/
struct _GstRTSPMediaFactoryClass {
GObjectClass parent_class;
gchar * (*gen_key) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
GstRTSPMedia * (*construct) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
void (*configure) (GstRTSPMediaFactory *factory, GstRTSPMedia *media);
void (*handle_message) (GstRTSPMediaFactory *factory, GstRTSPMedia *media,
GstMessage *message);
GstElement * (*get_element) (GstRTSPMediaFactory *factory, const GstRTSPUrl *url);
};
GType gst_rtsp_media_factory_get_type (void);
/* configuring the factory */
/* creating the factory */
GstRTSPMediaFactory * gst_rtsp_media_factory_new (void);
/* configuring the factory */
void gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory *factory,
const gchar *launch);
gchar * gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory *factory);
......@@ -92,8 +108,7 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFactory *
gboolean shared);
gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory);
/* creating the media bin from the factory */
/* creating the media from the factory and a url */
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
const GstRTSPUrl *url);
......
......@@ -19,6 +19,19 @@
#include "rtsp-media.h"
#define DEFAULT_SHARED FALSE
enum
{
PROP_0,
PROP_SHARED,
PROP_LAST
};
static void gst_rtsp_media_get_property (GObject *object, guint propid,
GValue *value, GParamSpec *pspec);
static void gst_rtsp_media_set_property (GObject *object, guint propid,
const GValue *value, GParamSpec *pspec);
static void gst_rtsp_media_finalize (GObject * obj);
G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
......@@ -30,7 +43,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_media_get_property;
gobject_class->set_property = gst_rtsp_media_set_property;
gobject_class->finalize = gst_rtsp_media_finalize;
g_object_class_install_property (gobject_class, PROP_SHARED,
g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared",
DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
......@@ -64,6 +83,36 @@ gst_rtsp_media_finalize (GObject * obj)
G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
}
static void
gst_rtsp_media_get_property (GObject *object, guint propid,
GValue *value, GParamSpec *pspec)
{
GstRTSPMedia *media = GST_RTSP_MEDIA (object);
switch (propid) {
case PROP_SHARED:
g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
static void
gst_rtsp_media_set_property (GObject *object, guint propid,
const GValue *value, GParamSpec *pspec)
{
GstRTSPMedia *media = GST_RTSP_MEDIA (object);
switch (propid) {
case PROP_SHARED:
gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
/**
* gst_rtsp_media_new:
*
......@@ -83,6 +132,38 @@ gst_rtsp_media_new (void)
return result;
}
/**
* gst_rtsp_media_set_shared:
* @media: a #GstRTSPMedia
* @shared: the new value
*
* Set or unset if the pipeline for @media can be shared will multiple clients.
* When @shared is %TRUE, client requests for this media will share the media
* pipeline.
*/
void
gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared)
{
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
media->shared = shared;
}
/**
* gst_rtsp_media_is_shared:
* @media: a #GstRTSPMedia
*
* Check if the pipeline for @media can be shared between multiple clients.
*
* Returns: %TRUE if the media can be shared between clients.
*/
gboolean
gst_rtsp_media_is_shared (GstRTSPMedia *media)
{
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
return media->shared;
}
/**
* gst_rtsp_media_n_streams:
......@@ -360,7 +441,6 @@ setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media)
return TRUE;
}
/**
* gst_rtsp_media_prepare:
* @obj: a #GstRTSPMedia
......@@ -379,6 +459,8 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
if (media->prepared)
goto was_prepared;
g_message ("preparing media %p", media);
media->pipeline = gst_pipeline_new ("media-pipeline");
gst_bin_add (GST_BIN_CAST (media->pipeline), media->element);
......@@ -388,8 +470,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
/* add stuf to the bin */
gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
ret = gst_element_set_state (media->pipeline, GST_STATE_READY);
/* link streams we already have */
n_streams = gst_rtsp_media_n_streams (media);
for (i = 0; i < n_streams; i++) {
GstRTSPMediaStream *stream;
......@@ -416,7 +497,7 @@ gst_rtsp_media_prepare (GstRTSPMedia *media)
goto state_failed;
}
/* no wait for all pads to be prerolled */
/* now wait for all pads to be prerolled */
ret = gst_element_get_state (media->pipeline, NULL, NULL, -1);
/* and back to PAUSED for live pipelines */
......
......@@ -88,6 +88,7 @@ struct _GstRTSPMediaStream {
/**
* GstRTSPMedia:
* @shared: if this media can be shared between clients
* @element: the data providing element
* @stream: the different streams provided by @element
* @prepared: if the media is prepared for streaming
......@@ -103,6 +104,8 @@ struct _GstRTSPMediaStream {
struct _GstRTSPMedia {
GObject parent;
gboolean shared;
GstElement *element;
GArray *streams;
gboolean prepared;
......@@ -126,13 +129,16 @@ GType gst_rtsp_media_get_type (void);
/* creating the media */
GstRTSPMedia * gst_rtsp_media_new (void);
/* dealing with the media */
guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared);
gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media);
/* prepare the media for playback */
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
/* dealing with the media */
guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
/* add destinations to a stream */
gboolean gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct);
gboolean gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment