Make the server handle arbitrary pipelines
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 22 Jan 2009 14:33:29 +0000 (15:33 +0100)
committerWim Taymans <wim@wtay.(none)>
Thu, 22 Jan 2009 14:33:29 +0000 (15:33 +0100)
Make GstMediaFactory an object that can instantiate GstMediaBin objects.
The GstMediaBin object has a handle to a bin with elements and to a list of
GstMediaStream objects that this bin produces.

Add GstMediaMapper that can map url mountpoints to GstMediaFactory objects along
with methods to register and remove those mappings.

Add methods and a property to GstRTSPServer to manage the GstMediaMapper object
used by the server instance.

Modify the example application so that it shows how to create custom pipelines
attached to a specific mount point.

Various misc cleanps.

14 files changed:
examples/main.c
gst/rtsp-server/Makefile.am
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-client.h
gst/rtsp-server/rtsp-media-factory.c
gst/rtsp-server/rtsp-media-factory.h
gst/rtsp-server/rtsp-media-mapping.c [new file with mode: 0644]
gst/rtsp-server/rtsp-media-mapping.h [new file with mode: 0644]
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h
gst/rtsp-server/rtsp-server.c
gst/rtsp-server/rtsp-server.h
gst/rtsp-server/rtsp-session.c
gst/rtsp-server/rtsp-session.h

index 41a1cb9..07b28cd 100644 (file)
@@ -26,6 +26,8 @@ main (int argc, char *argv[])
 {
   GMainLoop *loop;
   GstRTSPServer *server;
+  GstRTSPMediaMapping *mapping;
+  GstRTSPMediaFactory *factory;
 
   gst_init (&argc, &argv);
 
@@ -34,9 +36,41 @@ main (int argc, char *argv[])
   /* create a server instance */
   server = gst_rtsp_server_new ();
 
+  /* get the mapping for this server, every server has a default mapper object
+   * that be used to map uri mount points to media factories */
+  mapping = gst_rtsp_server_get_media_mapping (server);
+
+  /* make a media factory for a webcam. The default media factory can use
+   * gst-launch syntax to create pipelines. */
+  factory = gst_rtsp_media_factory_new ();
+#if 0
+  gst_rtsp_media_factory_set_launch (factory, "( "
+    "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
+    "queue ! videorate ! ffmpegcolorspace ! "
+    "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 "
+    "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! "
+    "amrnbenc ! rtpamrpay name=pay1 pt=97 "
+    ")");
+#endif
+  /* any launch line works as long as it contains elements named pay%d. Each
+   * element with pay%d names will be a stream */
+  gst_rtsp_media_factory_set_launch (factory, "( "
+    "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
+    "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 "
+    "audiotestsrc ! audio/x-raw-int,rate=8000 ! "
+    "alawenc ! rtppcmapay name=pay1 pt=97 "
+    ")");
+
+  /* attach the factory to the /camera url */
+  gst_rtsp_media_mapping_add_factory (mapping, "/camera", factory);
+
+  /* don't need the ref to the mapper anymore */
+  g_object_unref (mapping);
+
   /* attach the server to the default maincontext */
   gst_rtsp_server_attach (server, NULL);
 
+  /* start serving */
   g_main_loop_run (loop);
 
   return 0;
index 873619b..54ba251 100644 (file)
@@ -3,6 +3,7 @@ public_headers = \
                rtsp-client.h \
                rtsp-media.h \
                rtsp-media-factory.h \
+               rtsp-media-mapping.h \
                rtsp-session-pool.h \
                rtsp-session.h
                
@@ -10,7 +11,8 @@ c_sources = \
        rtsp-server.c \
        rtsp-client.c \
        rtsp-media.c \
-        rtsp-media-factory.c \
+       rtsp-media-factory.c \
+        rtsp-media-mapping.c \
        rtsp-session-pool.c \
        rtsp-session.c
        
index b884941..a3372da 100644 (file)
@@ -25,6 +25,8 @@
 
 #undef DEBUG
 
+static void gst_rtsp_client_finalize (GObject * obj);
+
 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
 
 static void
@@ -33,6 +35,8 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass)
   GObjectClass *gobject_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gst_rtsp_client_finalize;
 }
 
 static void
@@ -40,6 +44,12 @@ gst_rtsp_client_init (GstRTSPClient * client)
 {
 }
 
+static void
+gst_rtsp_client_finalize (GObject * obj)
+{
+  G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
+}
+
 /**
  * gst_rtsp_client_new:
  *
@@ -87,7 +97,7 @@ handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag
     goto service_unavailable;
 
   /* get a handle to the configuration of the media in the session */
-  media = gst_rtsp_session_get_media (session, client->media);
+  media = gst_rtsp_session_get_media (session, uri, client->factory);
   if (!media)
     goto not_found;
 
@@ -116,6 +126,7 @@ session_not_found:
   }
 service_unavailable:
   {
+    handle_generic_response (client, GST_RTSP_STS_OK, request);
     return FALSE;
   }
 not_found:
@@ -145,7 +156,7 @@ handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *
     goto service_unavailable;
 
   /* get a handle to the configuration of the media in the session */
-  media = gst_rtsp_session_get_media (session, client->media);
+  media = gst_rtsp_session_get_media (session, uri, client->factory);
   if (!media)
     goto not_found;
 
@@ -201,7 +212,7 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r
     goto service_unavailable;
 
   /* get a handle to the configuration of the media in the session */
-  media = gst_rtsp_session_get_media (session, client->media);
+  media = gst_rtsp_session_get_media (session, uri, client->factory);
   if (!media)
     goto not_found;
 
@@ -222,11 +233,11 @@ handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *r
 
   /* grab RTPInfo from the payloaders now */
   rtpinfo = g_string_new ("");
-  n_streams = gst_rtsp_media_n_streams (client->media);
+  n_streams = gst_rtsp_media_bin_n_streams (media->mediabin);
   for (i = 0; i < n_streams; i++) {
     GstRTSPMediaStream *stream;
 
-    stream = gst_rtsp_media_get_stream (client->media, i);
+    stream = gst_rtsp_media_bin_get_stream (media->mediabin, i);
 
     g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL);
     g_object_get (G_OBJECT (stream->payloader), "timestamp", &timestamp, NULL);
@@ -271,7 +282,7 @@ not_found:
 }
 
 static gboolean
-handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
+handle_setup_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request)
 {
   GstRTSPResult res;
   gchar *sessid;
@@ -279,6 +290,7 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *
   gchar **transports;
   gboolean have_transport;
   GstRTSPTransport *ct, *st;
+  GstRTSPUrl *uri;
   GstRTSPSession *session;
   gint i;
   GstRTSPLowerTrans supported;
@@ -290,9 +302,28 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *
   GstRTSPSessionMedia *media;
   gboolean need_session;
 
+  /* the uri contains the stream number we added in the SDP config, which is
+   * always /stream=%d so we need to strip that off */
+  if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK)
+    goto bad_url;
+
+  /* parse the stream we need to configure, look for the stream in the abspath
+   * first and then in the query. */
+  if (!(pos = strstr (uri->abspath, "/stream="))) {
+    if (!(pos = strstr (uri->query, "/stream=")))
+      goto bad_request;
+  }
+
+  /* we can mofify the parse uri in place */
+  *pos = '\0';
+
+  pos += strlen ("/stream=");
+  if (sscanf (pos, "%u", &streamid) != 1)
+    goto bad_request;
+
   /* find the media associated with the uri */
-  if (client->media == NULL) {
-    if ((client->media = gst_rtsp_media_new (uri)) == NULL)
+  if (client->factory == NULL) {
+    if ((client->factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri)) == NULL)
       goto not_found;
   }
 
@@ -351,20 +382,12 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *
   }
 
   /* get a handle to the configuration of the media in the session */
-  media = gst_rtsp_session_get_media (session, client->media);
+  media = gst_rtsp_session_get_media (session, uri->abspath, client->factory);
   if (!media)
     goto not_found;
 
-  /* parse the stream we need to configure */
-  if (!(pos = strstr (uri, "stream=")))
-    goto bad_request;
-
-  pos += strlen ("stream=");
-  if (sscanf (pos, "%u", &streamid) != 1)
-    goto bad_request;
-
   /* get a handle to the stream in the media */
-  stream = gst_rtsp_session_get_stream (media, streamid);
+  stream = gst_rtsp_session_media_get_stream (media, streamid);
 
   /* setup the server transport from the client transport */
   st = gst_rtsp_session_stream_set_transport (stream, inet_ntoa (client->address.sin_addr), ct);
@@ -387,9 +410,9 @@ handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *
   return TRUE;
 
   /* ERRORS */
-not_found:
+bad_url:
   {
-    handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
+    handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
     return FALSE;
   }
 bad_request:
@@ -397,6 +420,11 @@ bad_request:
     handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
     return FALSE;
   }
+not_found:
+  {
+    handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
+    return FALSE;
+  }
 session_not_found:
   {
     handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
@@ -414,46 +442,58 @@ service_unavailable:
   }
 }
 
+/* for the describe we must generate an SDP */
 static gboolean
-handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
+handle_describe_response (GstRTSPClient *client, const gchar *location, GstRTSPMessage *request)
 {
   GstRTSPMessage response = { 0 };
+  GstRTSPResult res;
   GstSDPMessage *sdp;
+  GstRTSPUrl *uri;
   guint n_streams, i;
   gchar *sdptext;
-  GstRTSPMedia *media;
-  GstElement *pipeline = NULL;
+  GstRTSPMediaFactory *factory;
+  GstRTSPMediaBin *mediabin;
+  GstElement *pipeline;
 
-  /* check what kind of format is accepted */
+  /* the uri contains the stream number we added in the SDP config, which is
+   * always /stream=%d so we need to strip that off */
+  if ((res = gst_rtsp_url_parse (location, &uri)) != GST_RTSP_OK)
+    goto bad_url;
 
+  /* find the factory for the uri first */
+  if (!(factory = gst_rtsp_media_mapping_find_factory (client->mapping, uri)))
+    goto no_factory;
 
-  /* for the describe we must generate an SDP */
-  if (!(media = gst_rtsp_media_new (uri)))
-    goto no_media;
+  /* check what kind of format is accepted */
 
-  /* create a pipeline if we have to */
-  if (pipeline == NULL) {
-    pipeline = gst_pipeline_new ("client-pipeline");
-  }
+  /* create a pipeline to preroll the media */
+  pipeline = gst_pipeline_new ("client-describe-pipeline");
 
-  /* prepare the media into the pipeline */
-  if (!gst_rtsp_media_prepare (media, GST_BIN (pipeline)))
-    goto no_media;
+  /* prepare the media and add it to the pipeline */
+  if (!(mediabin = gst_rtsp_media_factory_construct (factory, uri->abspath)))
+    goto no_media_bin;
+  
+  gst_bin_add (GST_BIN_CAST (pipeline), mediabin->element);
 
   /* link fakesink to all stream pads and set the pipeline to PLAYING */
-  n_streams = gst_rtsp_media_n_streams (media);
+  n_streams = gst_rtsp_media_bin_n_streams (mediabin);
   for (i = 0; i < n_streams; i++) {
     GstRTSPMediaStream *stream;
     GstElement *sink;
     GstPad *sinkpad;
+    GstPadLinkReturn lret;
 
-    stream = gst_rtsp_media_get_stream (media, i);
+    stream = gst_rtsp_media_bin_get_stream (mediabin, i);
 
     sink = gst_element_factory_make ("fakesink", NULL);
     gst_bin_add (GST_BIN (pipeline), sink);
 
     sinkpad = gst_element_get_static_pad (sink, "sink");
-    gst_pad_link (stream->srcpad, sinkpad);
+    lret = gst_pad_link (stream->srcpad, sinkpad);
+    if (lret != GST_PAD_LINK_OK) {
+      g_warning ("failed to link pad to sink: %d", lret);
+    }
     gst_object_unref (sinkpad);
   }
 
@@ -487,7 +527,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag
     gboolean first;
     GString *fmtp;
 
-    stream = gst_rtsp_media_get_stream (media, i);
+    stream = gst_rtsp_media_bin_get_stream (mediabin, i);
     gst_sdp_media_new (&smedia);
 
     s = gst_caps_get_structure (stream->caps, 0);
@@ -572,7 +612,7 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag
   /* go back to NULL */
   gst_element_set_state (pipeline, GST_STATE_NULL);
 
-  g_object_unref (media);
+  g_object_unref (factory);
 
   gst_object_unref (pipeline);
   pipeline = NULL;
@@ -590,11 +630,22 @@ handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessag
   return TRUE;
 
   /* ERRORS */
-no_media:
+bad_url:
+  {
+    handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
+    return FALSE;
+  }
+no_factory:
   {
     handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
     return FALSE;
   }
+no_media_bin:
+  {
+    handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
+    g_object_unref (factory);
+    return FALSE;
+  }
 }
 
 static void
@@ -713,7 +764,8 @@ handle_client (GstRTSPClient *client)
   /* ERRORS */
 receive_failed:
   {
-    g_print ("receive failed, disconnect client %p\n", client);
+    g_message ("receive failed %d (%s), disconnect client %p", res, 
+           gst_rtsp_strresult (res), client);
     gst_rtsp_connection_close (client->connection);
     g_object_unref (client);
     return NULL;
@@ -747,7 +799,7 @@ client_accept (GstRTSPClient *client, GIOChannel *channel)
    * connections */
   gst_poll_add_fd (conn->fdset, &conn->fd);
 
-  g_print ("added new client %p ip %s with fd %d\n", client,
+  g_message ("added new client %p ip %s with fd %d", client,
                inet_ntoa (client->address.sin_addr), conn->fd.fd);
 
   client->connection = conn;
@@ -769,7 +821,8 @@ accept_failed:
  * @pool: a #GstRTSPSessionPool
  *
  * Set @pool as the sessionpool for @client which it will use to find
- * or allocate sessions.
+ * or allocate sessions. the sessionpool is usually inherited from the server
+ * that created the client but can be overridden later.
  */
 void
 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
@@ -777,11 +830,13 @@ gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *poo
   GstRTSPSessionPool *old;
 
   old = client->pool;
-  if (pool)
-    g_object_ref (pool);
-  client->pool = pool;
-  if (old)
-    g_object_unref (old);
+  if (old != pool) {
+    if (pool)
+      g_object_ref (pool);
+    client->pool = pool;
+    if (old)
+      g_object_unref (old);
+  }
 }
 
 /**
@@ -804,43 +859,44 @@ gst_rtsp_client_get_session_pool (GstRTSPClient *client)
 }
 
 /**
- * gst_rtsp_client_set_media_factory:
+ * gst_rtsp_client_set_media_mapping:
  * @client: a #GstRTSPClient
- * @factory: a #GstRTSPMediaFactory
+ * @mapping: a #GstRTSPMediaMapping
  *
- * Set @factory as the media factory for @client which it will use to map urls
- * to media streams.
+ * Set @mapping as the media mapping for @client which it will use to map urls
+ * to media streams. These mapping is usually inherited from the server that
+ * created the client but can be overriden later.
  */
 void
-gst_rtsp_client_set_media_factory (GstRTSPClient *client, GstRTSPMediaFactory *factory)
+gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping)
 {
-  GstRTSPMediaFactory *old;
+  GstRTSPMediaMapping *old;
 
-  old = client->factory;
+  old = client->mapping;
 
-  if (old != factory) {
-    if (factory)
-      g_object_ref (factory);
-    client->factory = factory;
+  if (old != mapping) {
+    if (mapping)
+      g_object_ref (mapping);
+    client->mapping = mapping;
     if (old)
       g_object_unref (old);
   }
 }
 
 /**
- * gst_rtsp_client_get_media_factory:
+ * gst_rtsp_client_get_media_mapping:
  * @client: a #GstRTSPClient
  *
- * Get the #GstRTSPMediaFactory object that @client uses to manage its sessions.
+ * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
  *
- * Returns: a #GstRTSPMediaFactory, unref after usage.
+ * Returns: a #GstRTSPMediaMapping, unref after usage.
  */
-GstRTSPMediaFactory *
-gst_rtsp_client_get_media_factory (GstRTSPClient *client)
+GstRTSPMediaMapping *
+gst_rtsp_client_get_media_mapping (GstRTSPClient *client)
 {
-  GstRTSPMediaFactory *result;
+  GstRTSPMediaMapping *result;
 
-  if ((result = client->factory))
+  if ((result = client->mapping))
     g_object_ref (result);
 
   return result;
index 5dff20c..11a375c 100644 (file)
@@ -38,7 +38,7 @@
 #define __GST_RTSP_CLIENT_H__
 
 #include "rtsp-media.h"
-#include "rtsp-media-factory.h"
+#include "rtsp-media-mapping.h"
 #include "rtsp-session-pool.h"
 
 G_BEGIN_DECLS
@@ -75,9 +75,8 @@ struct _GstRTSPClient {
 
   GstRTSPSessionPool *pool;
 
-  GstRTSPMedia *media;
-  GstRTSPMediaFactory *factory;
-
+  GstRTSPMediaFactory  *factory;
+  GstRTSPMediaMapping  *mapping;
 };
 
 struct _GstRTSPClientClass {
@@ -92,9 +91,9 @@ void                  gst_rtsp_client_set_session_pool  (GstRTSPClient *client,
                                                          GstRTSPSessionPool *pool);
 GstRTSPSessionPool *  gst_rtsp_client_get_session_pool  (GstRTSPClient *client);
 
-void                  gst_rtsp_client_set_media_factory (GstRTSPClient *client, 
-                                                         GstRTSPMediaFactory *factory);
-GstRTSPMediaFactory * gst_rtsp_client_get_media_factory (GstRTSPClient *client);
+void                  gst_rtsp_client_set_media_mapping (GstRTSPClient *client, 
+                                                         GstRTSPMediaMapping *mapping);
+GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client);
 
 gboolean              gst_rtsp_client_accept            (GstRTSPClient *client, 
                                                          GIOChannel *channel);
index d402bad..1412d6a 100644 (file)
 
 #include "rtsp-media-factory.h"
 
-G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
+#define DEFAULT_LAUNCH         NULL
+
+enum
+{
+  PROP_0,
+  PROP_LAUNCH,
+  PROP_LAST
+};
 
+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 GstRTSPMedia * create_media (GstRTSPMediaFactory *factory, const gchar *url);
+static GstRTSPMediaBin * default_construct (GstRTSPMediaFactory *factory, const gchar *location);
+
+G_DEFINE_TYPE (GstRTSPMediaFactory, gst_rtsp_media_factory, G_TYPE_OBJECT);
 
 static void
 gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
@@ -32,9 +45,28 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
 
   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;
 
-  klass->create_media = create_media;
+  /**
+   * 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.
+   */
+  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));
+
+  klass->construct = default_construct;
 }
 
 static void
@@ -45,9 +77,51 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
 static void
 gst_rtsp_media_factory_finalize (GObject * obj)
 {
+  GstRTSPMediaFactory *factory = GST_RTSP_MEDIA_FACTORY (obj);
+
+  g_free (factory->launch);
+
   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;
+    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;
+    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 or %NULL when location did not contain a
+ * valid or understood URL.
+ */
 GstRTSPMediaFactory *
 gst_rtsp_media_factory_new (void)
 {
@@ -58,40 +132,172 @@ gst_rtsp_media_factory_new (void)
   return result;
 }
 
-static GstRTSPMedia *
-create_media (GstRTSPMediaFactory *factory, const gchar *url)
+/**
+ * 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)
 {
-  GstRTSPMedia *result;
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+  g_return_if_fail (launch != NULL);
 
-  result = gst_rtsp_media_new (url);
+  factory->launch = g_strdup (launch);
+}
+
+/**
+ * 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;
+
+  result = g_strdup (factory->launch);
 
   return result;
 }
 
-GstRTSPMedia *
-gst_rtsp_media_factory_create (GstRTSPMediaFactory *factory, const gchar *url)
+/**
+ * gst_rtsp_media_factory_construct:
+ * @factory: a #GstRTSPMediaFactory
+ * @location: the url used
+ *
+ * Prepare the media bin 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 #GstRTSPMediaBin if the media could be prepared.
+ */
+GstRTSPMediaBin *
+gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, const gchar *location)
 {
-  GstRTSPMedia *result = NULL;
+  GstRTSPMediaBin *res;
   GstRTSPMediaFactoryClass *klass;
 
   klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
 
-  if (klass->create_media)
-    result = klass->create_media (factory, url);
+  if (klass->construct)
+    res = klass->construct (factory, location);
+  else
+    res = NULL;
 
-  return result;
+  g_message ("constructed mediabin %p for location %s", res, location);
+
+  return res;
 }
 
-void
-gst_rtsp_media_factory_add (GstRTSPMediaFactory *factory, const gchar *path,
-    GType type)
+static void
+caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
 {
-  g_warning ("gst_rtsp_media_factory_add: not implemented");
+  if (stream->caps)
+    gst_caps_unref (stream->caps);
+  if ((stream->caps = GST_PAD_CAPS (pad)))
+    gst_caps_ref (stream->caps);
 }
-void
-gst_rtsp_media_factory_remove (GstRTSPMediaFactory *factory, const gchar *path,
-    GType type)
+
+static GstRTSPMediaBin *
+default_construct (GstRTSPMediaFactory *factory, const gchar *location)
 {
-  g_warning ("gst_rtsp_media_factory_remove: not implemented");
-}
+  GstRTSPMediaBin *bin;
+  GstRTSPMediaStream *stream;
+  GstElement *pay, *element;
+  GstPad * pad;
+  gint i;
+  GError *error = NULL;
 
+  /* 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;
+
+  if (error != NULL) {
+    /* a recoverable error was encountered */
+    g_warning ("recoverable parsing error: %s", error->message);
+    g_error_free (error);
+  }
+
+  bin = g_object_new (GST_TYPE_RTSP_MEDIA_BIN, NULL);
+  bin->element = element;
+
+  /* try to find all the payloader elements, they should be named 'pay%d'. for
+   * each of the payloaders we will create a stream, collect the source pad and
+   * add a notify::caps on the pad. */
+  for (i = 0; ; i++) {
+    gchar *name;
+
+    name = g_strdup_printf ("pay%d", i);
+
+    if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) {
+      /* no more payloaders found, we have found all the streams and we can
+       * end the loop */
+      g_free (name);
+      break;
+    }
+    
+    /* create the stream */
+    stream = g_new0 (GstRTSPMediaStream, 1);
+    stream->mediabin = bin;
+    stream->element = element;
+    stream->payloader = pay;
+    stream->idx = bin->streams->len;
+
+    pad = gst_element_get_static_pad (pay, "src");
+
+    /* ghost the pad of the payloader to the element */
+    stream->srcpad = gst_ghost_pad_new (name, pad);
+    gst_element_add_pad (stream->element, stream->srcpad);
+
+    stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream);
+    gst_object_unref (pad);
+
+    /* add stream now */
+    g_array_append_val (bin->streams, stream);
+    gst_object_unref (pay);
+
+    g_free (name);
+  }
+
+  return bin;
+
+  /* ERRORS */
+no_launch:
+  {
+    g_critical ("no launch line specified");
+    return NULL;
+  }
+parse_error:
+  {
+    g_critical ("could not parse launch syntax (%s): %s", factory->launch, 
+         (error ? error->message : "unknown reason"));
+    if (error)
+      g_error_free (error);
+    return NULL;
+  }
+}
index 1399649..5a98a96 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <gst/gst.h>
-
 #include <gst/rtsp/gstrtspurl.h>
 
 #include "rtsp-media.h"
@@ -28,7 +27,8 @@
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_RTSP_MEDIA_FACTORY              (gst_rtsp_media_get_type ())
+/* types for the media factory */
+#define GST_TYPE_RTSP_MEDIA_FACTORY              (gst_rtsp_media_factory_get_type ())
 #define GST_IS_RTSP_MEDIA_FACTORY(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY))
 #define GST_IS_RTSP_MEDIA_FACTORY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_FACTORY))
 #define GST_RTSP_MEDIA_FACTORY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_FACTORY, GstRTSPMediaFactoryClass))
@@ -42,33 +42,41 @@ typedef struct _GstRTSPMediaFactoryClass GstRTSPMediaFactoryClass;
 
 /**
  * GstRTSPMediaFactory:
+ * @launch: the launch description
+ * @streams: the array of #GstRTSPMediaStream objects for this media.
  *
- * Creates a #GstRTSPMedia object for a given url.
+ * The definition and logic for constructing the pipeline for a media. The media
+ * can contain multiple streams like audio and video.
  */
 struct _GstRTSPMediaFactory {
   GObject       parent;
+
+  gchar        *launch;
 };
 
+/**
+ * GstRTSPMediaFactoryClass:
+ * @construct: the vmethod that will be called when the factory has to create the
+ *       #GstRTSPMediaBin for @location.
+ *
+ * the #GstRTSPMediaFactory class structure.
+ */
 struct _GstRTSPMediaFactoryClass {
   GObjectClass  parent_class;
 
-  GstRTSPMedia * (*create_media)  (GstRTSPMediaFactory *factory, const gchar *url);
+  GstRTSPMediaBin * (*construct)   (GstRTSPMediaFactory *factory, const gchar *location);
 };
 
 GType                 gst_rtsp_media_factory_get_type     (void);
 
-/* creating a factory */
+/* configuring the factory */
 GstRTSPMediaFactory * gst_rtsp_media_factory_new          (void);
 
-/* creating a media */
-GstRTSPMedia *        gst_rtsp_media_factory_create       (GstRTSPMediaFactory *factory, const gchar *url);
-
+void                  gst_rtsp_media_factory_set_launch   (GstRTSPMediaFactory *factory, const gchar *launch);
+gchar *               gst_rtsp_media_factory_get_launch   (GstRTSPMediaFactory *factory);
 
-/* managing media GTypes to a path */
-void                  gst_rtsp_media_factory_add          (GstRTSPMediaFactory *factory, const gchar *path,
-                                                           GType type);
-void                  gst_rtsp_media_factory_remove       (GstRTSPMediaFactory *factory, const gchar *path,
-                                                           GType type);
+/* creating the media bin from the factory */
+GstRTSPMediaBin *     gst_rtsp_media_factory_construct    (GstRTSPMediaFactory *factory, const gchar *location);
 
 G_END_DECLS
 
diff --git a/gst/rtsp-server/rtsp-media-mapping.c b/gst/rtsp-server/rtsp-media-mapping.c
new file mode 100644 (file)
index 0000000..2471be7
--- /dev/null
@@ -0,0 +1,146 @@
+/* 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-mapping.h"
+
+G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT);
+
+static void gst_rtsp_media_mapping_finalize (GObject * obj);
+
+static GstRTSPMediaFactory * find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url);
+
+static void
+gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gst_rtsp_media_mapping_finalize;
+
+  klass->find_media = find_media;
+}
+
+static void
+gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping)
+{
+  mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal,
+                       g_free, g_object_unref);
+}
+
+static void
+gst_rtsp_media_mapping_finalize (GObject * obj)
+{
+  GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj);
+
+  g_hash_table_unref (mapping->mappings);
+
+  G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj);
+}
+
+GstRTSPMediaMapping *
+gst_rtsp_media_mapping_new (void)
+{
+  GstRTSPMediaMapping *result;
+
+  result = g_object_new (GST_TYPE_RTSP_MEDIA_MAPPING, NULL);
+
+  return result;
+}
+
+static GstRTSPMediaFactory *
+find_media (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url)
+{
+  GstRTSPMediaFactory *result;
+
+  /* find the location of the media in the hashtable */
+  result = g_hash_table_lookup (mapping->mappings, url->abspath);
+  if (result) 
+    g_object_ref (result);
+
+  g_message ("found media %p for url abspath %s", result, url->abspath);
+
+  return result;
+}
+
+/**
+ * gst_rtsp_media_mapping_find_factory:
+ * @mapping: a #GstRTSPMediaMapping
+ * @url: a url
+ *
+ * Find the #GstRTSPMediaFactory for @url from the mappings registered in @mapping.
+ *
+ * Returns: the #GstRTSPMediaFactory for @url. g_object_unref() after usage.
+ */
+GstRTSPMediaFactory *
+gst_rtsp_media_mapping_find_factory (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url)
+{
+  GstRTSPMediaFactory *result;
+  GstRTSPMediaMappingClass *klass;
+
+  klass = GST_RTSP_MEDIA_MAPPING_GET_CLASS (mapping);
+
+  if (klass->find_media)
+    result = klass->find_media (mapping, url);
+  else
+    result = NULL;
+
+  return result;
+}
+
+/**
+ * gst_rtsp_media_mapping_add_factory:
+ * @mapping: a #GstRTSPMediaMapping
+ * @path: a mount point
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Attach @factory to the mount point @path in @mapping.
+ *
+ * @path is of the form (/node)+. Any previous mapping will be freed.
+ *
+ * Ownership is taken of the reference on @factory so that @factory should not be
+ * used after calling this function.
+ */
+void
+gst_rtsp_media_mapping_add_factory (GstRTSPMediaMapping *mapping, const gchar *path,
+    GstRTSPMediaFactory *factory)
+{
+  g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping));
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+  g_return_if_fail (path != NULL);
+
+  g_hash_table_insert (mapping->mappings, g_strdup (path), factory);
+}
+
+/**
+ * gst_rtsp_media_mapping_remove_factory:
+ * @mapping: a #GstRTSPMediaMapping
+ * @path: a mount point
+ *
+ * Remove the #GstRTSPMediaFactory associated with @path in @mapping.
+ */
+void
+gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path)
+{
+  g_return_if_fail (GST_IS_RTSP_MEDIA_MAPPING (mapping));
+  g_return_if_fail (path != NULL);
+
+  g_hash_table_remove (mapping->mappings, path);
+}
+
diff --git a/gst/rtsp-server/rtsp-media-mapping.h b/gst/rtsp-server/rtsp-media-mapping.h
new file mode 100644 (file)
index 0000000..6544246
--- /dev/null
@@ -0,0 +1,76 @@
+/* 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 <gst/gst.h>
+
+#include <gst/rtsp/gstrtspurl.h>
+
+#include "rtsp-media-factory.h"
+
+#ifndef __GST_RTSP_MEDIA_MAPPING_H__
+#define __GST_RTSP_MEDIA_MAPPING_H__
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTSP_MEDIA_MAPPING              (gst_rtsp_media_mapping_get_type ())
+#define GST_IS_RTSP_MEDIA_MAPPING(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_MAPPING))
+#define GST_IS_RTSP_MEDIA_MAPPING_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_MAPPING))
+#define GST_RTSP_MEDIA_MAPPING_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass))
+#define GST_RTSP_MEDIA_MAPPING(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMapping))
+#define GST_RTSP_MEDIA_MAPPING_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_MAPPING, GstRTSPMediaMappingClass))
+#define GST_RTSP_MEDIA_MAPPING_CAST(obj)         ((GstRTSPMediaMapping*)(obj))
+#define GST_RTSP_MEDIA_MAPPING_CLASS_CAST(klass) ((GstRTSPMediaMappingClass*)(klass))
+
+typedef struct _GstRTSPMediaMapping GstRTSPMediaMapping;
+typedef struct _GstRTSPMediaMappingClass GstRTSPMediaMappingClass;
+
+/**
+ * GstRTSPMediaMapping:
+ * @mappings: the mountpoint to media mappings
+ *
+ * Creates a #GstRTSPMedia object for a given url.
+ */
+struct _GstRTSPMediaMapping {
+  GObject       parent;
+
+  GHashTable   *mappings;
+};
+
+struct _GstRTSPMediaMappingClass {
+  GObjectClass  parent_class;
+
+  GstRTSPMediaFactory * (*find_media)  (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url);
+};
+
+GType                 gst_rtsp_media_mapping_get_type     (void);
+
+/* creating a mapping */
+GstRTSPMediaMapping * gst_rtsp_media_mapping_new          (void);
+
+/* finding a media factory */
+GstRTSPMediaFactory * gst_rtsp_media_mapping_find_factory   (GstRTSPMediaMapping *mapping, const GstRTSPUrl *url);
+
+/* managing media to a path */
+void                  gst_rtsp_media_mapping_add_factory    (GstRTSPMediaMapping *mapping, const gchar *path,
+                                                             GstRTSPMediaFactory *factory);
+void                  gst_rtsp_media_mapping_remove_factory (GstRTSPMediaMapping *mapping, const gchar *path);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_MEDIA_MAPPING_H__ */
index 13425d0..036d09f 100644 (file)
 
 #include "rtsp-media.h"
 
-G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
+static void gst_rtsp_media_bin_finalize (GObject * obj);
 
-static void gst_rtsp_media_finalize (GObject * obj);
+G_DEFINE_TYPE (GstRTSPMediaBin, gst_rtsp_media_bin, G_TYPE_OBJECT);
 
 static void
-gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
+gst_rtsp_media_bin_class_init (GstRTSPMediaBinClass * klass)
 {
   GObjectClass *gobject_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
 
-  gobject_class->finalize = gst_rtsp_media_finalize;
+  gobject_class->finalize = gst_rtsp_media_bin_finalize;
 }
 
 static void
-gst_rtsp_media_init (GstRTSPMedia * media)
+gst_rtsp_media_bin_init (GstRTSPMediaBin * bin)
 {
-  media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
+  bin->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
 }
 
 static void
@@ -45,218 +45,59 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream *stream)
 }
 
 static void
-gst_rtsp_media_finalize (GObject * obj)
+gst_rtsp_media_bin_finalize (GObject * obj)
 {
-  GstRTSPMedia *media;
+  GstRTSPMediaBin *bin;
   guint i;
 
-  media = GST_RTSP_MEDIA (obj);
+  bin = GST_RTSP_MEDIA_BIN (obj);
 
-  g_free (media->location);
-  gst_rtsp_url_free (media->url);
-
-  for (i = 0; i < media->streams->len; i++) {
+  for (i = 0; i < bin->streams->len; i++) {
     GstRTSPMediaStream *stream;
 
-    stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
+    stream = g_array_index (bin->streams, GstRTSPMediaStream *, i);
 
     gst_rtsp_media_stream_free (stream);
   }
-  g_array_free (media->streams, TRUE);
-
-  G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
-}
-
-/**
- * gst_rtsp_media_new:
- * @location: the URL of the media
- *
- * Create a new #GstRTSPMedia instance.
- *
- * Returns: a new #GstRTSPMedia object or %NULL when location did not contain a
- * valid or understood URL.
- */
-GstRTSPMedia *
-gst_rtsp_media_new (const gchar *location)
-{
-  GstRTSPMedia *result;
-  GstRTSPUrl *url;
-
-  url = NULL;
-
-  if (gst_rtsp_url_parse (location, &url) != GST_RTSP_OK)
-    goto invalid_url;
-
-  result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
-  result->location = g_strdup (location);
-  result->url = url;
-
-  return result;
-
-  /* ERRORS */
-invalid_url:
-  {
-    return NULL;
-  }
-}
-
-static void
-caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
-{
-  if (stream->caps)
-    gst_caps_unref (stream->caps);
-  if ((stream->caps = GST_PAD_CAPS (pad)))
-    gst_caps_ref (stream->caps);
-}
-
-/**
- * gst_rtsp_media_prepare:
- * @media: a #GstRTSPMedia
- * @bin: the parent bin to create the elements in.
- *
- * Prepare the media object so that it creates its streams. Implementations
- * should crate the needed gstreamer elements and add them to @bin. No state
- * changes should be performed on them yet.
- *
- * One or more GstRTSPMediaStream objects should be added to @media with the
- * srcpad member set to a source pad that produces buffer of type 
- * application/x-rtp.
- *
- * Returns: %TRUE if the media could be prepared.
- */
-gboolean
-gst_rtsp_media_prepare (GstRTSPMedia *media, GstBin *bin)
-{
-  GstRTSPMediaStream *stream;
-  GstElement *pay, *element;
-  GstPad * pad;
-  gint i;
-
-  /* if we're already prepared we must exit */
-  g_return_val_if_fail (media->prepared == FALSE, FALSE);
-
-  g_print ("%s\n", media->url->abspath);
-
-  if (g_str_has_prefix (media->url->abspath, "/camera")) {
-    /* live */
-    element = gst_parse_launch ("( "
-       "v4l2src ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
-       "queue ! videorate ! ffmpegcolorspace ! "
-       "x264enc bitrate=300 ! rtph264pay name=pay0 pt=96 "
-       "alsasrc ! audio/x-raw-int,rate=8000 ! queue ! "
-       "amrnbenc ! rtpamrpay name=pay1 pt=97 "
-       ")", NULL);
-  }
-  else if (g_str_has_prefix (media->url->abspath, "/h264")) {
-    /* transcode h264 */
-    element = gst_parse_launch ("( uridecodebin "
-       "uri=file:///home/cschalle/Videos/mi2.avi ! "
-       "x264enc bitrate=300 ! rtph264pay name=pay0 )", NULL);
-  }
-  else if (g_str_has_prefix (media->url->abspath, "/theora")) {
-    /* transcode theora */
-    element = gst_parse_launch ("( uridecodebin "
-       "uri=file:///home/wim/data/mi2.avi ! "
-       "theoraenc ! rtptheorapay name=pay0 )", NULL);
-  }
-  else if (g_str_has_prefix (media->url->abspath, "/macpclinux")) {
-    /* theora/vorbis */
-    element = gst_parse_launch ("( filesrc "
-       "location=/home/cschalle/Videos/mac_pc_linux_2.ogg ! oggdemux name=d ! "
-       "queue ! theoraparse ! rtptheorapay name=pay0 "
-       "d. ! queue ! vorbisparse ! rtpvorbispay name=pay1 )", NULL);
-  }
-  else if (g_str_has_prefix (media->url->abspath, "/rtspproxy")) {
-    /* proxy RTSP transcode */
-    element = gst_parse_launch ("( uridecodebin "
-       "uri=rtsp://ia300135.us.archive.org:554/0/items/uncovered_interviews/uncovered_interviews_3_256kb.mp4 ! "
-       "x264enc bitrate=1800 ! rtph264pay name=pay0 )", NULL);
-  }
-  else if (g_str_has_prefix (media->url->abspath, "/httpproxy")) {
-    /* proxy HTTP transcode */
-    element = gst_parse_launch ("( uridecodebin "
-       "uri=http://movies.apple.com/movies/fox/maxpayne/maxpayne-tlre_h480.mov name=d "
-       "d. ! queue ! x264enc bitrate=1800 ! rtph264pay name=pay0 pt=96 "
-       "d. ! queue ! faac ! rtpmp4gpay name=pay1 pt=97 )", NULL);
-  }
-  else
-    return FALSE;
-
-  gst_bin_add (bin, element);
-
-  for (i = 0; ; i++) {
-    gchar *name;
-
-    name = g_strdup_printf ("pay%d", i);
-
-    if (!(pay = gst_bin_get_by_name (GST_BIN (element), name))) {
-      g_free (name);
-      break;
-    }
-    
-    /* create the stream */
-    stream = g_new0 (GstRTSPMediaStream, 1);
-    stream->media = media;
-    stream->element = element;
-    stream->payloader = pay;
-    stream->idx = media->streams->len;
-
-    pad = gst_element_get_static_pad (pay, "src");
-
-    stream->srcpad = gst_ghost_pad_new (name, pad);
-    gst_element_add_pad (stream->element, stream->srcpad);
-
-    stream->caps_sig = g_signal_connect (pad, "notify::caps", (GCallback) caps_notify, stream);
-    gst_object_unref (pad);
-
-    /* add stream now */
-    g_array_append_val (media->streams, stream);
-    gst_object_unref (pay);
-
-    g_free (name);
-  }
-
-  media->prepared = TRUE;
+  g_array_free (bin->streams, TRUE);
 
-  return TRUE;
+  G_OBJECT_CLASS (gst_rtsp_media_bin_parent_class)->finalize (obj);
 }
 
 /**
- * gst_rtsp_media_n_streams:
- * @media: a #GstRTSPMedia
+ * gst_rtsp_media_bin_n_streams:
+ * @media: a #GstRTSPMediaBin
  *
- * Get the number of streams in this media.
+ * Get the number of streams in this mediabin.
  *
  * Returns: The number of streams.
  */
 guint
-gst_rtsp_media_n_streams (GstRTSPMedia *media)
+gst_rtsp_media_bin_n_streams (GstRTSPMediaBin *bin)
 {
-  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
-  g_return_val_if_fail (media->prepared, 0);
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), 0);
 
-  return media->streams->len;
+  return bin->streams->len;
 }
 
 /**
- * gst_rtsp_media_get_stream:
- * @media: a #GstRTSPMedia
+ * gst_rtsp_media_bin_get_stream:
+ * @bin: a #GstRTSPMediaBin
  * @idx: the stream index
  *
- * Retrieve the stream with index @idx from @media.
+ * Retrieve the stream with index @idx from @bin.
  *
  * Returns: the #GstRTSPMediaStream at index @idx.
  */
 GstRTSPMediaStream *
-gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx)
+gst_rtsp_media_bin_get_stream (GstRTSPMediaBin *bin, guint idx)
 {
   GstRTSPMediaStream *res;
   
-  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
-  g_return_val_if_fail (media->prepared, 0);
-  g_return_val_if_fail (idx < media->streams->len, NULL);
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_BIN (bin), NULL);
+  g_return_val_if_fail (idx < bin->streams->len, NULL);
 
-  res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
+  res = g_array_index (bin->streams, GstRTSPMediaStream *, idx);
 
   return res;
 }
index f96ab1f..8c6e64d 100644 (file)
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_RTSP_MEDIA              (gst_rtsp_media_get_type ())
-#define GST_IS_RTSP_MEDIA(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA))
-#define GST_IS_RTSP_MEDIA_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA))
-#define GST_RTSP_MEDIA_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass))
-#define GST_RTSP_MEDIA(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA, GstRTSPMedia))
-#define GST_RTSP_MEDIA_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA, GstRTSPMediaClass))
-#define GST_RTSP_MEDIA_CAST(obj)         ((GstRTSPMedia*)(obj))
-#define GST_RTSP_MEDIA_CLASS_CAST(klass) ((GstRTSPMediaClass*)(klass))
+/* types for the media bin */
+#define GST_TYPE_RTSP_MEDIA_BIN              (gst_rtsp_media_bin_get_type ())
+#define GST_IS_RTSP_MEDIA_BIN(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_BIN))
+#define GST_IS_RTSP_MEDIA_BIN_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_BIN))
+#define GST_RTSP_MEDIA_BIN_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass))
+#define GST_RTSP_MEDIA_BIN(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBin))
+#define GST_RTSP_MEDIA_BIN_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_BIN, GstRTSPMediaBinClass))
+#define GST_RTSP_MEDIA_BIN_CAST(obj)         ((GstRTSPMediaBin*)(obj))
+#define GST_RTSP_MEDIA_BIN_CLASS_CAST(klass) ((GstRTSPMediaBinClass*)(klass))
 
-typedef struct _GstRTSPMedia GstRTSPMedia;
 typedef struct _GstRTSPMediaStream GstRTSPMediaStream;
-typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
+typedef struct _GstRTSPMediaBin GstRTSPMediaBin;
+typedef struct _GstRTSPMediaBinClass GstRTSPMediaBinClass;
 
 /**
  * GstRTSPMediaStream:
@@ -51,7 +52,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
  * The definition of a media stream. The streams are identified by @id.
  */
 struct _GstRTSPMediaStream {
-  GstRTSPMedia *media;
+  GstRTSPMediaBin *mediabin;
 
   guint       idx;
 
@@ -63,33 +64,28 @@ struct _GstRTSPMediaStream {
 };
 
 /**
- * GstRTSPMedia:
+ * GstRTSPMediaBin:
+ * @media: the owner #GstRTSPMedia
  *
- * The definition and logic for constructing the pipeline for a media. The media
- * can contain multiple streams like audio and video.
+ * A class that contains the elements to handle the media
+ * provided by @media.
  */
-struct _GstRTSPMedia {
+struct _GstRTSPMediaBin {
   GObject       parent;
 
-  gchar        *location;
-  GstRTSPUrl   *url;
-
-  gboolean      prepared;
+  GstElement   *element;
   GArray       *streams;
 };
 
-struct _GstRTSPMediaClass {
+struct _GstRTSPMediaBinClass {
   GObjectClass  parent_class;
 };
 
-GType                gst_rtsp_media_get_type             (void);
-
-GstRTSPMedia *       gst_rtsp_media_new                  (const gchar *name);
-
-gboolean             gst_rtsp_media_prepare              (GstRTSPMedia *media, GstBin *bin);
+GType                 gst_rtsp_media_bin_get_type         (void);
 
-guint                gst_rtsp_media_n_streams            (GstRTSPMedia *media);
-GstRTSPMediaStream * gst_rtsp_media_get_stream           (GstRTSPMedia *media, guint idx);
+/* dealing with the media bin */
+guint                 gst_rtsp_media_bin_n_streams        (GstRTSPMediaBin *bin);
+GstRTSPMediaStream *  gst_rtsp_media_bin_get_stream       (GstRTSPMediaBin *bin, guint idx);
 
 G_END_DECLS
 
index cea1bf0..b34bc80 100644 (file)
@@ -31,7 +31,7 @@ enum
   PROP_BACKLOG,
   PROP_PORT,
   PROP_POOL,
-  PROP_FACTORY,
+  PROP_MAPPING,
   PROP_LAST
 };
 
@@ -88,14 +88,14 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
       g_param_spec_object ("pool", "Pool", "The session pool to use for client session",
           GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   /**
-   * GstRTSPServer::factory
+   * GstRTSPServer::mapping
    *
-   * The media factory to use for this server. By default the server has no
-   * media factories and thus cannot map urls to media streams.
+   * The media mapping to use for this server. By default the server has no
+   * media mapping and thus cannot map urls to media streams.
    */
-  g_object_class_install_property (gobject_class, PROP_POOL,
-      g_param_spec_object ("factory", "Factory", "The media factory to use for client session",
-          GST_TYPE_RTSP_MEDIA_FACTORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAPPING,
+      g_param_spec_object ("mapping", "Mapping", "The media mapping to use for client session",
+          GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   klass->accept_client = gst_rtsp_server_accept_client;
 }
@@ -106,6 +106,7 @@ gst_rtsp_server_init (GstRTSPServer * server)
   server->server_port = DEFAULT_PORT;
   server->backlog = DEFAULT_BACKLOG;
   server->pool = gst_rtsp_session_pool_new ();
+  server->mapping = gst_rtsp_media_mapping_new ();
 }
 
 /**
@@ -202,13 +203,19 @@ gst_rtsp_server_get_backlog (GstRTSPServer *server)
 void
 gst_rtsp_server_set_session_pool (GstRTSPServer *server, GstRTSPSessionPool *pool)
 {
+  GstRTSPSessionPool *old;
+
   g_return_if_fail (GST_IS_RTSP_SERVER (server));
 
-  if (server->pool)
-    g_object_unref (server->pool);
-  if (pool)
-    g_object_ref (pool);
-  server->pool = pool;
+  old = server->pool;
+
+  if (old != pool) {
+    if (pool)
+      g_object_ref (pool);
+    server->pool = pool;
+    if (old)
+      g_object_unref (old);
+  }
 }
 
 
@@ -235,25 +242,25 @@ gst_rtsp_server_get_session_pool (GstRTSPServer *server)
 }
 
 /**
- * gst_rtsp_server_set_media_factory:
+ * gst_rtsp_server_set_media_mapping:
  * @server: a #GstRTSPServer
- * @factory: a #GstRTSPMediaFactory
+ * @mapping: a #GstRTSPMediaMapping
  *
- * configure @factory to be used as the media factory of @server.
+ * configure @mapping to be used as the media mapping of @server.
  */
 void
-gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *factory)
+gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping)
 {
-  GstRTSPMediaFactory *old;
+  GstRTSPMediaMapping *old;
 
   g_return_if_fail (GST_IS_RTSP_SERVER (server));
 
-  old = server->factory;
+  old = server->mapping;
 
-  if (old != factory) {
-    if (factory)
-      g_object_ref (factory);
-    server->factory = factory;
+  if (old != mapping) {
+    if (mapping)
+      g_object_ref (mapping);
+    server->mapping = mapping;
     if (old)
       g_object_unref (old);
   }
@@ -261,22 +268,22 @@ gst_rtsp_server_set_media_factory (GstRTSPServer *server, GstRTSPMediaFactory *f
 
 
 /**
- * gst_rtsp_server_get_media_factory:
+ * gst_rtsp_server_get_media_mapping:
  * @server: a #GstRTSPServer
  *
- * Get the #GstRTSPMediaFactory used as the media factory of @server.
+ * Get the #GstRTSPMediaMapping used as the media mapping of @server.
  *
- * Returns: the #GstRTSPMediaFactory of @server. g_object_unref() after
+ * Returns: the #GstRTSPMediaMapping of @server. g_object_unref() after
  * usage.
  */
-GstRTSPMediaFactory *
-gst_rtsp_server_get_media_factory (GstRTSPServer *server)
+GstRTSPMediaMapping *
+gst_rtsp_server_get_media_mapping (GstRTSPServer *server)
 {
-  GstRTSPMediaFactory *result;
+  GstRTSPMediaMapping *result;
 
   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
 
-  if ((result = server->factory))
+  if ((result = server->mapping))
     g_object_ref (result);
 
   return result;
@@ -298,8 +305,8 @@ gst_rtsp_server_get_property (GObject *object, guint propid,
     case PROP_POOL:
       g_value_take_object (value, gst_rtsp_server_get_session_pool (server));
       break;
-    case PROP_FACTORY:
-      g_value_take_object (value, gst_rtsp_server_get_media_factory (server));
+    case PROP_MAPPING:
+      g_value_take_object (value, gst_rtsp_server_get_media_mapping (server));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
@@ -322,8 +329,8 @@ gst_rtsp_server_set_property (GObject *object, guint propid,
     case PROP_POOL:
       gst_rtsp_server_set_session_pool (server, g_value_get_object (value));
       break;
-    case PROP_FACTORY:
-      gst_rtsp_server_set_media_factory (server, g_value_get_object (value));
+    case PROP_MAPPING:
+      gst_rtsp_server_set_media_mapping (server, g_value_get_object (value));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
@@ -440,7 +447,7 @@ gst_rtsp_server_accept_client (GstRTSPServer *server, GIOChannel *channel)
   gst_rtsp_client_set_session_pool (client, server->pool);
 
   /* set the session pool that this client should use */
-  gst_rtsp_client_set_media_factory (client, server->factory);
+  gst_rtsp_client_set_media_mapping (client, server->mapping);
 
   /* accept connections for that client, this function returns after accepting
    * the connection and will run the remainder of the communication with the
index 5dd5629..277b841 100644 (file)
@@ -34,7 +34,7 @@
 #include <gst/gst.h>
 
 #include "rtsp-session-pool.h"
-#include "rtsp-media-factory.h"
+#include "rtsp-media-mapping.h"
 #include "rtsp-client.h"
 
 #ifndef __GST_RTSP_SERVER_H__
@@ -72,8 +72,8 @@ struct _GstRTSPServer {
   /* sessions on this server */
   GstRTSPSessionPool *pool;
 
-  /* media factory for this server */
-  GstRTSPMediaFactory *factory;
+  /* media mapper for this server */
+  GstRTSPMediaMapping *mapping;
 };
 
 /**
@@ -103,8 +103,8 @@ gint                  gst_rtsp_server_get_backlog          (GstRTSPServer *serve
 void                  gst_rtsp_server_set_session_pool     (GstRTSPServer *server, GstRTSPSessionPool *pool);
 GstRTSPSessionPool *  gst_rtsp_server_get_session_pool     (GstRTSPServer *server);
 
-void                  gst_rtsp_server_set_media_factory    (GstRTSPServer *server, GstRTSPMediaFactory *factory);
-GstRTSPMediaFactory * gst_rtsp_server_get_media_factory    (GstRTSPServer *server);
+void                  gst_rtsp_server_set_media_mapping    (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
+GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping    (GstRTSPServer *server);
 
 gboolean              gst_rtsp_server_io_func              (GIOChannel *channel, GIOCondition condition,
                                                            GstRTSPServer *server);
index 6eddd12..dd608c7 100644 (file)
@@ -62,8 +62,8 @@ gst_rtsp_session_free_media (GstRTSPSessionMedia *media)
 
   gst_element_set_state (media->pipeline, GST_STATE_NULL);
 
-  if (media->media)
-    g_object_unref (media->media);
+  if (media->factory)
+    g_object_unref (media->factory);
 
   for (walk = media->streams; walk; walk = g_list_next (walk)) {
     GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data; 
@@ -98,14 +98,15 @@ gst_rtsp_session_finalize (GObject * obj)
 /**
  * gst_rtsp_session_get_media:
  * @sess: a #GstRTSPSession
- * @media: a #GstRTSPSessionMedia
+ * @location: the url for the media
+ * @factory: a #GstRTSPMediaFactory
  *
- * Get or create the session information for @media.
+ * Get or create the session information for @factory.
  *
- * Returns: the configuration for @media in @sess.
+ * Returns: the configuration for @factory in @sess.
  */
 GstRTSPSessionMedia *
-gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media)
+gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, GstRTSPMediaFactory *factory)
 {
   GstRTSPSessionMedia *result;
   GList *walk;
@@ -115,19 +116,22 @@ gst_rtsp_session_get_media (GstRTSPSession *sess, GstRTSPMedia *media)
   for (walk = sess->medias; walk; walk = g_list_next (walk)) {
     result = (GstRTSPSessionMedia *) walk->data; 
 
-    if (result->media == media)
+    if (result->factory == factory)
       break;
 
     result = NULL;
   }
   if (result == NULL) {
     result = g_new0 (GstRTSPSessionMedia, 1);
-    result->media = media;
+    result->factory = factory;
     result->pipeline = gst_pipeline_new ("pipeline");
 
-    /* prepare media into the pipeline */
-    if (!gst_rtsp_media_prepare (media, GST_BIN (result->pipeline)))
+    /* construct media and add to the pipeline */
+    result->mediabin = gst_rtsp_media_factory_construct (factory, location);
+    if (result->mediabin == NULL)
       goto no_media;
+    
+    gst_bin_add (GST_BIN_CAST (result->pipeline), result->mediabin->element);
 
     result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
 
@@ -149,7 +153,7 @@ no_media:
 }
 
 /**
- * gst_rtsp_session_get_stream:
+ * gst_rtsp_session_media_get_stream:
  * @media: a #GstRTSPSessionMedia
  * @idx: the stream index
  *
@@ -159,7 +163,7 @@ no_media:
  * is unreffed.
  */
 GstRTSPSessionStream *
-gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx)
+gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx)
 {
   GstRTSPSessionStream *result;
   GList *walk;
@@ -178,7 +182,7 @@ gst_rtsp_session_get_stream (GstRTSPSessionMedia *media, guint idx)
     result = g_new0 (GstRTSPSessionStream, 1);
     result->idx = idx;
     result->media = media;
-    result->media_stream = gst_rtsp_media_get_stream (media->media, idx);
+    result->media_stream = gst_rtsp_media_bin_get_stream (media->mediabin, idx);
 
     media->streams = g_list_prepend (media->streams, result);
   }
index c87a139..5db5ba8 100644 (file)
@@ -22,6 +22,7 @@
 #include <gst/rtsp/gstrtsptransport.h>
 
 #include "rtsp-media.h"
+#include "rtsp-media-factory.h"
 
 #ifndef __GST_RTSP_SESSION_H__
 #define __GST_RTSP_SESSION_H__
@@ -87,10 +88,11 @@ struct _GstRTSPSessionMedia
   GstRTSPSession *session;
 
   /* the media we are handling */
-  GstRTSPMedia *media;
+  GstRTSPMediaFactory *factory;
 
   /* the pipeline for the media */
   GstElement   *pipeline;
+  GstRTSPMediaBin *mediabin;
 
   /* RTP session manager */
   GstElement   *rtpbin;
@@ -125,15 +127,16 @@ GType                  gst_rtsp_session_get_type             (void);
 
 GstRTSPSession *       gst_rtsp_session_new                  (const gchar *sessionid);
 
-GstRTSPSessionMedia *  gst_rtsp_session_get_media            (GstRTSPSession *sess,
-                                                              GstRTSPMedia *media);
-GstRTSPSessionStream * gst_rtsp_session_get_stream           (GstRTSPSessionMedia *media,
-                                                              guint idx);
+GstRTSPSessionMedia *  gst_rtsp_session_get_media            (GstRTSPSession *sess, const gchar *location,
+                                                              GstRTSPMediaFactory *factory);
 
 GstStateChangeReturn   gst_rtsp_session_media_play           (GstRTSPSessionMedia *media);
 GstStateChangeReturn   gst_rtsp_session_media_pause          (GstRTSPSessionMedia *media);
 GstStateChangeReturn   gst_rtsp_session_media_stop           (GstRTSPSessionMedia *media);
 
+GstRTSPSessionStream * gst_rtsp_session_media_get_stream     (GstRTSPSessionMedia *media,
+                                                              guint idx);
+
 GstRTSPTransport *     gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream,
                                                               const gchar *destination,
                                                               GstRTSPTransport *ct);