mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-01 06:01:04 +00:00
878 lines
24 KiB
C
878 lines
24 KiB
C
/* GStreamer
|
|
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
|
|
*
|
|
* 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., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "rtsp-media-factory.h"
|
|
|
|
#define DEFAULT_LAUNCH NULL
|
|
#define DEFAULT_SHARED FALSE
|
|
#define DEFAULT_EOS_SHUTDOWN FALSE
|
|
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
|
|
#define DEFAULT_BUFFER_SIZE 0x80000
|
|
#define DEFAULT_MULTICAST_GROUP "224.2.0.1"
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_LAUNCH,
|
|
PROP_SHARED,
|
|
PROP_EOS_SHUTDOWN,
|
|
PROP_PROTOCOLS,
|
|
PROP_BUFFER_SIZE,
|
|
PROP_MULTICAST_GROUP,
|
|
PROP_LAST
|
|
};
|
|
|
|
enum
|
|
{
|
|
SIGNAL_MEDIA_CONSTRUCTED,
|
|
SIGNAL_MEDIA_CONFIGURE,
|
|
SIGNAL_LAST
|
|
};
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
|
#define GST_CAT_DEFAULT rtsp_media_debug
|
|
|
|
static guint gst_rtsp_media_factory_signals[SIGNAL_LAST] = { 0 };
|
|
|
|
static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
|
|
GValue * value, GParamSpec * pspec);
|
|
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 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);
|
|
static GstElement *default_create_pipeline (GstRTSPMediaFactory * factory,
|
|
GstRTSPMedia * media);
|
|
|
|
G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
|
|
|
|
static void
|
|
gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
|
|
gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->get_property = gst_rtsp_media_factory_get_property;
|
|
gobject_class->set_property = gst_rtsp_media_factory_set_property;
|
|
gobject_class->finalize = gst_rtsp_media_factory_finalize;
|
|
|
|
/**
|
|
* GstRTSPMediaFactory::launch
|
|
*
|
|
* The gst_parse_launch() line to use for constructing the pipeline in the
|
|
* default prepare vmethod.
|
|
*
|
|
* The pipeline description should return a GstBin as the toplevel element
|
|
* which can be accomplished by enclosing the dscription with brackets '('
|
|
* ')'.
|
|
*
|
|
* The description should return a pipeline with payloaders named pay0, pay1,
|
|
* etc.. Each of the payloaders will result in a stream.
|
|
*
|
|
* Support for dynamic payloaders can be accomplished by adding payloaders
|
|
* named dynpay0, dynpay1, etc..
|
|
*/
|
|
g_object_class_install_property (gobject_class, PROP_LAUNCH,
|
|
g_param_spec_string ("launch", "Launch",
|
|
"A launch description of the pipeline", DEFAULT_LAUNCH,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
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));
|
|
|
|
g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
|
|
g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
|
|
"Send EOS down the pipeline before shutting down",
|
|
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
|
|
g_param_spec_flags ("protocols", "Protocols",
|
|
"Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
|
|
DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
|
|
g_param_spec_uint ("buffer-size", "Buffer Size",
|
|
"The kernel UDP buffer size to use", 0, G_MAXUINT,
|
|
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
|
|
g_param_spec_string ("multicast-group", "Multicast Group",
|
|
"The Multicast group to send media to",
|
|
DEFAULT_MULTICAST_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
|
|
g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
|
|
media_constructed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
|
|
|
|
gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE] =
|
|
g_signal_new ("media-configure", G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
|
|
media_configure), NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1, GST_TYPE_RTSP_MEDIA);
|
|
|
|
klass->gen_key = default_gen_key;
|
|
klass->get_element = default_get_element;
|
|
klass->construct = default_construct;
|
|
klass->configure = default_configure;
|
|
klass->create_pipeline = default_create_pipeline;
|
|
|
|
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
|
|
"GstRTSPMediaFactory");
|
|
}
|
|
|
|
static void
|
|
gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
|
|
{
|
|
factory->launch = g_strdup (DEFAULT_LAUNCH);
|
|
factory->shared = DEFAULT_SHARED;
|
|
factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
|
factory->protocols = DEFAULT_PROTOCOLS;
|
|
factory->buffer_size = DEFAULT_BUFFER_SIZE;
|
|
factory->multicast_group = g_strdup (DEFAULT_MULTICAST_GROUP);
|
|
|
|
g_mutex_init (&factory->lock);
|
|
g_mutex_init (&factory->medias_lock);
|
|
factory->medias = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
g_free, g_object_unref);
|
|
}
|
|
|
|
static void
|
|
gst_rtsp_media_factory_finalize (GObject * obj)
|
|
{
|
|
GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
|
|
|
|
g_hash_table_unref (factory->medias);
|
|
g_mutex_clear (&factory->medias_lock);
|
|
g_free (factory->launch);
|
|
g_free (factory->multicast_group);
|
|
g_mutex_clear (&factory->lock);
|
|
if (factory->auth)
|
|
g_object_unref (factory->auth);
|
|
|
|
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
|
|
}
|
|
|
|
static void
|
|
gst_rtsp_media_factory_get_property (GObject * object, guint propid,
|
|
GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
|
|
|
|
switch (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;
|
|
case PROP_EOS_SHUTDOWN:
|
|
g_value_set_boolean (value,
|
|
gst_rtsp_media_factory_is_eos_shutdown (factory));
|
|
break;
|
|
case PROP_PROTOCOLS:
|
|
g_value_set_flags (value, gst_rtsp_media_factory_get_protocols (factory));
|
|
break;
|
|
case PROP_BUFFER_SIZE:
|
|
g_value_set_uint (value,
|
|
gst_rtsp_media_factory_get_buffer_size (factory));
|
|
break;
|
|
case PROP_MULTICAST_GROUP:
|
|
g_value_take_string (value,
|
|
gst_rtsp_media_factory_get_multicast_group (factory));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_rtsp_media_factory_set_property (GObject * object, guint propid,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (object);
|
|
|
|
switch (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;
|
|
case PROP_EOS_SHUTDOWN:
|
|
gst_rtsp_media_factory_set_eos_shutdown (factory,
|
|
g_value_get_boolean (value));
|
|
break;
|
|
case PROP_PROTOCOLS:
|
|
gst_rtsp_media_factory_set_protocols (factory, g_value_get_flags (value));
|
|
break;
|
|
case PROP_BUFFER_SIZE:
|
|
gst_rtsp_media_factory_set_buffer_size (factory,
|
|
g_value_get_uint (value));
|
|
break;
|
|
case PROP_MULTICAST_GROUP:
|
|
gst_rtsp_media_factory_set_multicast_group (factory,
|
|
g_value_get_string (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_new:
|
|
*
|
|
* Create a new #GstRTSPMediaFactory instance.
|
|
*
|
|
* Returns: a new #GstRTSPMediaFactory object.
|
|
*/
|
|
GstRTSPMediaFactory *
|
|
gst_rtsp_media_factory_new (void)
|
|
{
|
|
GstRTSPMediaFactory *result;
|
|
|
|
result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY, NULL);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_launch:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
* @launch: the launch description
|
|
*
|
|
*
|
|
* The gst_parse_launch() line to use for constructing the pipeline in the
|
|
* default prepare vmethod.
|
|
*
|
|
* The pipeline description should return a GstBin as the toplevel element
|
|
* which can be accomplished by enclosing the dscription with brackets '('
|
|
* ')'.
|
|
*
|
|
* The description should return a pipeline with payloaders named pay0, pay1,
|
|
* etc.. Each of the payloaders will result in a stream.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_launch (GstRTSPMediaFactory * factory,
|
|
const gchar * launch)
|
|
{
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
g_return_if_fail (launch != NULL);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
g_free (factory->launch);
|
|
factory->launch = g_strdup (launch);
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_get_launch:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
*
|
|
* Get the gst_parse_launch() pipeline description that will be used in the
|
|
* default prepare vmethod.
|
|
*
|
|
* Returns: the configured launch description. g_free() after usage.
|
|
*/
|
|
gchar *
|
|
gst_rtsp_media_factory_get_launch (GstRTSPMediaFactory * factory)
|
|
{
|
|
gchar *result;
|
|
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
result = g_strdup (factory->launch);
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
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));
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
factory->shared = shared;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
result = factory->shared;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_eos_shutdown:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
* @eos_shutdown: the new value
|
|
*
|
|
* Configure if media created from this factory will have an EOS sent to the
|
|
* pipeline before shutdown.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFactory * factory,
|
|
gboolean eos_shutdown)
|
|
{
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
factory->eos_shutdown = eos_shutdown;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_is_eos_shutdown:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
*
|
|
* Get if media created from this factory will have an EOS event sent to the
|
|
* pipeline before shutdown.
|
|
*
|
|
* Returns: %TRUE if the media will receive EOS before shutdown.
|
|
*/
|
|
gboolean
|
|
gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
|
|
{
|
|
gboolean result;
|
|
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
result = factory->eos_shutdown;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_buffer_size:
|
|
* @factory: a #GstRTSPMedia
|
|
* @size: the new value
|
|
*
|
|
* Set the kernel UDP buffer size.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
|
|
guint size)
|
|
{
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
factory->buffer_size = size;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_get_buffer_size:
|
|
* @factory: a #GstRTSPMedia
|
|
*
|
|
* Get the kernel UDP buffer size.
|
|
*
|
|
* Returns: the kernel UDP buffer size.
|
|
*/
|
|
guint
|
|
gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
|
|
{
|
|
guint result;
|
|
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
result = factory->buffer_size;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_multicast_group:
|
|
* @factory: a #GstRTSPMedia
|
|
* @mc: the new multicast group
|
|
*
|
|
* Set the multicast group that media from @factory will be streamed to.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_multicast_group (GstRTSPMediaFactory * factory,
|
|
const gchar * mc)
|
|
{
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
g_free (factory->multicast_group);
|
|
factory->multicast_group = g_strdup (mc);
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_get_multicast_group:
|
|
* @factory: a #GstRTSPMedia
|
|
*
|
|
* Get the multicast group that media from @factory will be streamed to.
|
|
*
|
|
* Returns: the multicast group
|
|
*/
|
|
gchar *
|
|
gst_rtsp_media_factory_get_multicast_group (GstRTSPMediaFactory * factory)
|
|
{
|
|
gchar *result;
|
|
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
result = g_strdup (factory->multicast_group);
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_auth:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
* @auth: a #GstRTSPAuth
|
|
*
|
|
* configure @auth to be used as the authentication manager of @factory.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
|
|
GstRTSPAuth * auth)
|
|
{
|
|
GstRTSPAuth *old;
|
|
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
|
|
old = factory->auth;
|
|
|
|
if (old != auth) {
|
|
if (auth)
|
|
g_object_ref (auth);
|
|
factory->auth = auth;
|
|
if (old)
|
|
g_object_unref (old);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_get_auth:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
*
|
|
* Get the #GstRTSPAuth used as the authentication manager of @factory.
|
|
*
|
|
* Returns: the #GstRTSPAuth of @factory. g_object_unref() after
|
|
* usage.
|
|
*/
|
|
GstRTSPAuth *
|
|
gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
|
|
{
|
|
GstRTSPAuth *result;
|
|
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
|
|
|
|
if ((result = factory->auth))
|
|
g_object_ref (result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_set_protocols:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
* @protocols: the new flags
|
|
*
|
|
* Configure the allowed lower transport for @factory.
|
|
*/
|
|
void
|
|
gst_rtsp_media_factory_set_protocols (GstRTSPMediaFactory * factory,
|
|
GstRTSPLowerTrans protocols)
|
|
{
|
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
|
|
|
factory->protocols = protocols;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_get_protocols:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
*
|
|
* Get the allowed protocols of @factory.
|
|
*
|
|
* Returns: a #GstRTSPLowerTrans
|
|
*/
|
|
GstRTSPLowerTrans
|
|
gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
|
|
{
|
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory),
|
|
GST_RTSP_LOWER_TRANS_UNKNOWN);
|
|
|
|
return factory->protocols;
|
|
}
|
|
|
|
static gboolean
|
|
compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
|
|
{
|
|
return (media1 == media2);
|
|
}
|
|
|
|
static void
|
|
media_unprepared (GstRTSPMedia * media, GstRTSPMediaFactory * factory)
|
|
{
|
|
g_mutex_lock (&factory->medias_lock);
|
|
g_hash_table_foreach_remove (factory->medias, (GHRFunc) compare_media, media);
|
|
g_mutex_unlock (&factory->medias_lock);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_media_factory_construct:
|
|
* @factory: a #GstRTSPMediaFactory
|
|
* @url: the url used
|
|
*
|
|
* Prepare the media object and create its streams. Implementations
|
|
* should create the needed gstreamer elements and add them to the result
|
|
* object. No state changes should be performed on them yet.
|
|
*
|
|
* One or more GstRTSPMediaStream objects should be added to the result with
|
|
* the srcpad member set to a source pad that produces buffer of type
|
|
* application/x-rtp.
|
|
*
|
|
* Returns: a new #GstRTSPMedia if the media could be prepared.
|
|
*/
|
|
GstRTSPMedia *
|
|
gst_rtsp_media_factory_construct (GstRTSPMediaFactory * factory,
|
|
const GstRTSPUrl * url)
|
|
{
|
|
gchar *key;
|
|
GstRTSPMedia *media;
|
|
GstRTSPMediaFactoryClass *klass;
|
|
|
|
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
|
|
|
|
/* 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
|
|
media = NULL;
|
|
|
|
if (media == NULL) {
|
|
/* nothing cached found, try to create one */
|
|
if (klass->construct) {
|
|
media = klass->construct (factory, url);
|
|
if (media)
|
|
g_signal_emit (factory,
|
|
gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED], 0, media,
|
|
NULL);
|
|
} else
|
|
media = NULL;
|
|
|
|
if (media) {
|
|
/* configure the media */
|
|
if (klass->configure)
|
|
klass->configure (factory, media);
|
|
|
|
g_signal_emit (factory,
|
|
gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONFIGURE], 0, media,
|
|
NULL);
|
|
|
|
/* 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;
|
|
}
|
|
if (!gst_rtsp_media_is_reusable (media)) {
|
|
/* when not reusable, connect to the unprepare signal to remove the item
|
|
* from our cache when it gets unprepared */
|
|
g_signal_connect (media, "unprepared", (GCallback) media_unprepared,
|
|
factory);
|
|
}
|
|
}
|
|
}
|
|
g_mutex_unlock (&factory->medias_lock);
|
|
|
|
if (key)
|
|
g_free (key);
|
|
|
|
GST_INFO ("constructed media %p for url %s", media, url->abspath);
|
|
|
|
return media;
|
|
}
|
|
|
|
static gchar *
|
|
default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
|
|
{
|
|
gchar *result;
|
|
const gchar *pre_query;
|
|
const gchar *query;
|
|
|
|
pre_query = url->query ? "?" : "";
|
|
query = url->query ? url->query : "";
|
|
|
|
result =
|
|
g_strdup_printf ("%u%s%s%s", url->port, url->abspath, pre_query, query);
|
|
|
|
return result;
|
|
}
|
|
|
|
static GstElement *
|
|
default_get_element (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
|
|
{
|
|
GstElement *element;
|
|
GError *error = NULL;
|
|
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
/* we need a parse syntax */
|
|
if (factory->launch == NULL)
|
|
goto no_launch;
|
|
|
|
/* parse the user provided launch line */
|
|
element = gst_parse_launch (factory->launch, &error);
|
|
if (element == NULL)
|
|
goto parse_error;
|
|
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
if (error != NULL) {
|
|
/* a recoverable error was encountered */
|
|
GST_WARNING ("recoverable parsing error: %s", error->message);
|
|
g_error_free (error);
|
|
}
|
|
return element;
|
|
|
|
/* ERRORS */
|
|
no_launch:
|
|
{
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
g_critical ("no launch line specified");
|
|
return NULL;
|
|
}
|
|
parse_error:
|
|
{
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
g_critical ("could not parse launch syntax (%s): %s", factory->launch,
|
|
(error ? error->message : "unknown reason"));
|
|
if (error)
|
|
g_error_free (error);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* try to find all the payloader elements, they should be named 'pay%d'. for
|
|
* each of the payloaders we will create a stream and collect the source pad. */
|
|
void
|
|
gst_rtsp_media_factory_collect_streams (GstRTSPMediaFactory * factory,
|
|
const GstRTSPUrl * url, GstRTSPMedia * media)
|
|
{
|
|
GstElement *element, *elem;
|
|
GstPad *pad;
|
|
gint i;
|
|
GstRTSPMediaStream *stream;
|
|
gboolean have_elem;
|
|
|
|
element = media->element;
|
|
|
|
have_elem = TRUE;
|
|
for (i = 0; have_elem; i++) {
|
|
gchar *name;
|
|
|
|
have_elem = FALSE;
|
|
|
|
name = g_strdup_printf ("pay%d", i);
|
|
if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
|
|
/* create the stream */
|
|
stream = g_new0 (GstRTSPMediaStream, 1);
|
|
stream->payloader = elem;
|
|
|
|
GST_INFO ("found stream %d with payloader %p", i, elem);
|
|
|
|
pad = gst_element_get_static_pad (elem, "src");
|
|
|
|
/* ghost the pad of the payloader to the element */
|
|
stream->srcpad = gst_ghost_pad_new (name, pad);
|
|
gst_pad_set_active (stream->srcpad, TRUE);
|
|
gst_element_add_pad (media->element, stream->srcpad);
|
|
gst_object_unref (elem);
|
|
|
|
/* add stream now */
|
|
g_array_append_val (media->streams, stream);
|
|
have_elem = TRUE;
|
|
}
|
|
g_free (name);
|
|
|
|
name = g_strdup_printf ("dynpay%d", i);
|
|
if ((elem = gst_bin_get_by_name (GST_BIN (element), name))) {
|
|
/* a stream that will dynamically create pads to provide RTP packets */
|
|
|
|
GST_INFO ("found dynamic element %d, %p", i, elem);
|
|
|
|
media->dynamic = g_list_prepend (media->dynamic, elem);
|
|
|
|
have_elem = TRUE;
|
|
}
|
|
g_free (name);
|
|
}
|
|
}
|
|
|
|
static GstRTSPMedia *
|
|
default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
|
|
{
|
|
GstRTSPMedia *media;
|
|
GstElement *element;
|
|
GstRTSPMediaFactoryClass *klass;
|
|
|
|
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
|
|
|
|
if (!klass->create_pipeline)
|
|
goto no_create;
|
|
|
|
if (klass->get_element)
|
|
element = klass->get_element (factory, url);
|
|
else
|
|
element = NULL;
|
|
if (element == NULL)
|
|
goto no_element;
|
|
|
|
/* create a new empty media */
|
|
media = gst_rtsp_media_new ();
|
|
media->element = element;
|
|
|
|
media->pipeline = klass->create_pipeline (factory, media);
|
|
if (media->pipeline == NULL)
|
|
goto no_pipeline;
|
|
|
|
gst_rtsp_media_factory_collect_streams (factory, url, media);
|
|
|
|
return media;
|
|
|
|
/* ERRORS */
|
|
no_create:
|
|
{
|
|
g_critical ("no create_pipeline function");
|
|
return NULL;
|
|
}
|
|
no_element:
|
|
{
|
|
g_critical ("could not create element");
|
|
return NULL;
|
|
}
|
|
no_pipeline:
|
|
{
|
|
g_critical ("can't create pipeline");
|
|
g_object_unref (media);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static GstElement *
|
|
default_create_pipeline (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
|
|
{
|
|
GstElement *pipeline;
|
|
|
|
if (media->element == NULL)
|
|
goto no_element;
|
|
|
|
pipeline = gst_pipeline_new ("media-pipeline");
|
|
gst_bin_add (GST_BIN_CAST (pipeline), media->element);
|
|
|
|
return pipeline;
|
|
|
|
/* ERRORS */
|
|
no_element:
|
|
{
|
|
g_critical ("no element");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
|
|
{
|
|
gboolean shared, eos_shutdown;
|
|
guint size;
|
|
GstRTSPAuth *auth;
|
|
GstRTSPLowerTrans protocols;
|
|
gchar *mc;
|
|
|
|
/* configure the sharedness */
|
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
|
shared = factory->shared;
|
|
eos_shutdown = factory->eos_shutdown;
|
|
size = factory->buffer_size;
|
|
protocols = factory->protocols;
|
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
|
|
|
gst_rtsp_media_set_shared (media, shared);
|
|
gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
|
|
gst_rtsp_media_set_buffer_size (media, size);
|
|
gst_rtsp_media_set_protocols (media, protocols);
|
|
|
|
if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
|
|
gst_rtsp_media_set_auth (media, auth);
|
|
g_object_unref (auth);
|
|
}
|
|
if ((mc = gst_rtsp_media_factory_get_multicast_group (factory))) {
|
|
gst_rtsp_media_set_multicast_group (media, mc);
|
|
g_free (mc);
|
|
}
|
|
}
|