small cleanup
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-media-factory-uri.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <string.h>
21
22 #include "rtsp-media-factory-uri.h"
23
24 #define GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE(obj)  \
25     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_URI, GstRTSPMediaFactoryURIPrivate))
26
27 struct _GstRTSPMediaFactoryURIPrivate
28 {
29   GMutex lock;
30   gchar *uri;
31   gboolean use_gstpay;
32
33   GstCaps *raw_vcaps;
34   GstCaps *raw_acaps;
35   GList *demuxers;
36   GList *payloaders;
37   GList *decoders;
38 };
39
40 #define DEFAULT_URI         NULL
41 #define DEFAULT_USE_GSTPAY  FALSE
42
43 enum
44 {
45   PROP_0,
46   PROP_URI,
47   PROP_USE_GSTPAY,
48   PROP_LAST
49 };
50
51
52 #define RAW_VIDEO_CAPS \
53     "video/x-raw"
54
55 #define RAW_AUDIO_CAPS \
56     "audio/x-raw"
57
58 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS (RAW_VIDEO_CAPS);
59 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS (RAW_AUDIO_CAPS);
60
61 typedef struct
62 {
63   GstRTSPMediaFactoryURI *factory;
64   guint pt;
65 } FactoryData;
66
67 static void
68 free_data (FactoryData * data)
69 {
70   g_object_unref (data->factory);
71   g_free (data);
72 }
73
74 static const gchar *factory_key = "GstRTSPMediaFactoryURI";
75
76 GST_DEBUG_CATEGORY_STATIC (rtsp_media_factory_uri_debug);
77 #define GST_CAT_DEFAULT rtsp_media_factory_uri_debug
78
79 static void gst_rtsp_media_factory_uri_get_property (GObject * object,
80     guint propid, GValue * value, GParamSpec * pspec);
81 static void gst_rtsp_media_factory_uri_set_property (GObject * object,
82     guint propid, const GValue * value, GParamSpec * pspec);
83 static void gst_rtsp_media_factory_uri_finalize (GObject * obj);
84
85 static GstElement *rtsp_media_factory_uri_create_element (GstRTSPMediaFactory *
86     factory, const GstRTSPUrl * url);
87
88 G_DEFINE_TYPE (GstRTSPMediaFactoryURI, gst_rtsp_media_factory_uri,
89     GST_TYPE_RTSP_MEDIA_FACTORY);
90
91 static void
92 gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
93 {
94   GObjectClass *gobject_class;
95   GstRTSPMediaFactoryClass *mediafactory_class;
96
97   gobject_class = G_OBJECT_CLASS (klass);
98   mediafactory_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass);
99
100   gobject_class->get_property = gst_rtsp_media_factory_uri_get_property;
101   gobject_class->set_property = gst_rtsp_media_factory_uri_set_property;
102   gobject_class->finalize = gst_rtsp_media_factory_uri_finalize;
103
104   /**
105    * GstRTSPMediaFactoryURI::uri:
106    *
107    * The uri of the resource that will be served by this factory.
108    */
109   g_object_class_install_property (gobject_class, PROP_URI,
110       g_param_spec_string ("uri", "URI",
111           "The URI of the resource to stream", DEFAULT_URI,
112           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
113   /**
114    * GstRTSPMediaFactoryURI::use-gstpay:
115    *
116    * Allow the usage of gstpay in order to avoid decoding of compressed formats
117    * without a payloader.
118    */
119   g_object_class_install_property (gobject_class, PROP_USE_GSTPAY,
120       g_param_spec_boolean ("use-gstpay", "Use gstpay",
121           "Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY,
122           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
123
124   mediafactory_class->create_element = rtsp_media_factory_uri_create_element;
125
126   GST_DEBUG_CATEGORY_INIT (rtsp_media_factory_uri_debug, "rtspmediafactoryuri",
127       0, "GstRTSPMediaFactoryUri");
128 }
129
130 typedef struct
131 {
132   GList *demux;
133   GList *payload;
134   GList *decode;
135 } FilterData;
136
137 static gboolean
138 payloader_filter (GstPluginFeature * feature, FilterData * data)
139 {
140   const gchar *klass;
141   GstElementFactory *fact;
142   GList **list = NULL;
143
144   /* we only care about element factories */
145   if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
146     return FALSE;
147
148   if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL)
149     return FALSE;
150
151   fact = GST_ELEMENT_FACTORY_CAST (feature);
152
153   klass = gst_element_factory_get_metadata (fact, GST_ELEMENT_METADATA_KLASS);
154
155   if (strstr (klass, "Decoder"))
156     list = &data->decode;
157   else if (strstr (klass, "Demux"))
158     list = &data->demux;
159   else if (strstr (klass, "Parser") && strstr (klass, "Codec"))
160     list = &data->demux;
161   else if (strstr (klass, "Payloader") && strstr (klass, "RTP"))
162     list = &data->payload;
163
164   if (list) {
165     GST_DEBUG ("adding %s", GST_OBJECT_NAME (fact));
166     *list = g_list_prepend (*list, gst_object_ref (fact));
167   }
168
169   return FALSE;
170 }
171
172 static void
173 gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
174 {
175   GstRTSPMediaFactoryURIPrivate *priv =
176       GST_RTSP_MEDIA_FACTORY_URI_GET_PRIVATE (factory);
177   FilterData data = { NULL, NULL, NULL };
178
179   GST_DEBUG_OBJECT (factory, "new");
180
181   factory->priv = priv;
182
183   priv->uri = g_strdup (DEFAULT_URI);
184   priv->use_gstpay = DEFAULT_USE_GSTPAY;
185   g_mutex_init (&priv->lock);
186
187   /* get the feature list using the filter */
188   gst_registry_feature_filter (gst_registry_get (), (GstPluginFeatureFilter)
189       payloader_filter, FALSE, &data);
190   /* sort */
191   priv->demuxers =
192       g_list_sort (data.demux, gst_plugin_feature_rank_compare_func);
193   priv->payloaders =
194       g_list_sort (data.payload, gst_plugin_feature_rank_compare_func);
195   priv->decoders =
196       g_list_sort (data.decode, gst_plugin_feature_rank_compare_func);
197
198   priv->raw_vcaps = gst_static_caps_get (&raw_video_caps);
199   priv->raw_acaps = gst_static_caps_get (&raw_audio_caps);
200 }
201
202 static void
203 gst_rtsp_media_factory_uri_finalize (GObject * obj)
204 {
205   GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj);
206   GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
207
208   GST_DEBUG_OBJECT (factory, "finalize");
209
210   g_free (priv->uri);
211   gst_plugin_feature_list_free (priv->demuxers);
212   gst_plugin_feature_list_free (priv->payloaders);
213   gst_plugin_feature_list_free (priv->decoders);
214   gst_caps_unref (priv->raw_vcaps);
215   gst_caps_unref (priv->raw_acaps);
216   g_mutex_clear (&priv->lock);
217
218   G_OBJECT_CLASS (gst_rtsp_media_factory_uri_parent_class)->finalize (obj);
219 }
220
221 static void
222 gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid,
223     GValue * value, GParamSpec * pspec)
224 {
225   GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object);
226   GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
227
228   switch (propid) {
229     case PROP_URI:
230       g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
231       break;
232     case PROP_USE_GSTPAY:
233       g_value_set_boolean (value, priv->use_gstpay);
234       break;
235     default:
236       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
237   }
238 }
239
240 static void
241 gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid,
242     const GValue * value, GParamSpec * pspec)
243 {
244   GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (object);
245   GstRTSPMediaFactoryURIPrivate *priv = factory->priv;
246
247   switch (propid) {
248     case PROP_URI:
249       gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
250       break;
251     case PROP_USE_GSTPAY:
252       priv->use_gstpay = g_value_get_boolean (value);
253       break;
254     default:
255       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
256   }
257 }
258
259 /**
260  * gst_rtsp_media_factory_uri_new:
261  *
262  * Create a new #GstRTSPMediaFactoryURI instance.
263  *
264  * Returns: a new #GstRTSPMediaFactoryURI object.
265  */
266 GstRTSPMediaFactoryURI *
267 gst_rtsp_media_factory_uri_new (void)
268 {
269   GstRTSPMediaFactoryURI *result;
270
271   result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY_URI, NULL);
272
273   return result;
274 }
275
276 /**
277  * gst_rtsp_media_factory_uri_set_uri:
278  * @factory: a #GstRTSPMediaFactory
279  * @uri: the uri the stream
280  *
281  * Set the URI of the resource that will be streamed by this factory.
282  */
283 void
284 gst_rtsp_media_factory_uri_set_uri (GstRTSPMediaFactoryURI * factory,
285     const gchar * uri)
286 {
287   GstRTSPMediaFactoryURIPrivate *priv;
288
289   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory));
290   g_return_if_fail (uri != NULL);
291
292   priv = factory->priv;
293
294   g_mutex_lock (&priv->lock);
295   g_free (priv->uri);
296   priv->uri = g_strdup (uri);
297   g_mutex_unlock (&priv->lock);
298 }
299
300 /**
301  * gst_rtsp_media_factory_uri_get_uri:
302  * @factory: a #GstRTSPMediaFactory
303  *
304  * Get the URI that will provide media for this factory.
305  *
306  * Returns: the configured URI. g_free() after usage.
307  */
308 gchar *
309 gst_rtsp_media_factory_uri_get_uri (GstRTSPMediaFactoryURI * factory)
310 {
311   GstRTSPMediaFactoryURIPrivate *priv;
312   gchar *result;
313
314   g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY_URI (factory), NULL);
315
316   priv = factory->priv;
317
318   g_mutex_lock (&priv->lock);
319   result = g_strdup (priv->uri);
320   g_mutex_unlock (&priv->lock);
321
322   return result;
323 }
324
325 static GstElementFactory *
326 find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps)
327 {
328   GstRTSPMediaFactoryURIPrivate *priv = urifact->priv;
329   GList *list;
330   GstElementFactory *factory = NULL;
331   gboolean autoplug_more = FALSE;
332
333   /* first find a demuxer that can link */
334   list = gst_element_factory_list_filter (priv->demuxers, caps,
335       GST_PAD_SINK, FALSE);
336
337   if (list) {
338     GstStructure *structure = gst_caps_get_structure (caps, 0);
339     gboolean parsed = FALSE;
340
341     gst_structure_get_boolean (structure, "parsed", &parsed);
342
343     /* Avoid plugging parsers in a loop. This is not 100% correct, as some
344      * parsers don't set parsed=true in caps. We should do something like
345      * decodebin does and track decode chains and elements plugged in those
346      * chains...
347      */
348     if (parsed) {
349       GList *walk;
350       const gchar *klass;
351
352       for (walk = list; walk; walk = walk->next) {
353         factory = GST_ELEMENT_FACTORY (walk->data);
354         klass = gst_element_factory_get_metadata (factory,
355             GST_ELEMENT_METADATA_KLASS);
356         if (strstr (klass, "Parser"))
357           /* caps have parsed=true, so skip this parser to avoid loops */
358           continue;
359
360         autoplug_more = TRUE;
361         break;
362       }
363     } else {
364       /* caps don't have parsed=true set and we have a demuxer/parser */
365       autoplug_more = TRUE;
366     }
367
368     gst_plugin_feature_list_free (list);
369   }
370
371   if (autoplug_more)
372     /* we have a demuxer, try that one first */
373     return NULL;
374
375   /* no demuxer try a depayloader */
376   list = gst_element_factory_list_filter (priv->payloaders, caps,
377       GST_PAD_SINK, FALSE);
378
379   if (list == NULL) {
380     if (priv->use_gstpay) {
381       /* no depayloader or parser/demuxer, use gstpay when allowed */
382       factory = gst_element_factory_find ("rtpgstpay");
383     } else {
384       /* no depayloader, try a decoder, we'll get to a payloader for a decoded
385        * video or audio format, worst case. */
386       list = gst_element_factory_list_filter (priv->decoders, caps,
387           GST_PAD_SINK, FALSE);
388
389       if (list != NULL) {
390         /* we have a decoder, try that one first */
391         gst_plugin_feature_list_free (list);
392         return NULL;
393       }
394     }
395   }
396
397   if (list != NULL) {
398     factory = GST_ELEMENT_FACTORY_CAST (list->data);
399     g_object_ref (factory);
400     gst_plugin_feature_list_free (list);
401   }
402   return factory;
403 }
404
405 static gboolean
406 autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps,
407     GstElement * element)
408 {
409   FactoryData *data;
410   GstElementFactory *factory;
411
412   GST_DEBUG ("found pad %s:%s of caps %" GST_PTR_FORMAT,
413       GST_DEBUG_PAD_NAME (pad), caps);
414
415   data = g_object_get_data (G_OBJECT (element), factory_key);
416
417   if (!(factory = find_payloader (data->factory, caps)))
418     goto no_factory;
419
420   /* we found a payloader, stop autoplugging so we can plug the
421    * payloader. */
422   GST_DEBUG ("found factory %s",
423       gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
424   gst_object_unref (factory);
425
426   return FALSE;
427
428   /* ERRORS */
429 no_factory:
430   {
431     /* no payloader, continue autoplugging */
432     GST_DEBUG ("no payloader found");
433     return TRUE;
434   }
435 }
436
437 static void
438 pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element)
439 {
440   GstRTSPMediaFactoryURI *urifact;
441   GstRTSPMediaFactoryURIPrivate *priv;
442   FactoryData *data;
443   GstElementFactory *factory;
444   GstElement *payloader;
445   GstCaps *caps;
446   GstPad *sinkpad, *srcpad, *ghostpad;
447   GstElement *convert;
448   gchar *padname;
449
450   GST_DEBUG ("added pad %s:%s", GST_DEBUG_PAD_NAME (pad));
451
452   /* link the element now and expose the pad */
453   data = g_object_get_data (G_OBJECT (element), factory_key);
454   urifact = data->factory;
455   priv = urifact->priv;
456
457   /* ref to make refcounting easier later */
458   gst_object_ref (pad);
459   padname = gst_pad_get_name (pad);
460
461   /* get pad caps first, then call get_caps, then fail */
462   if ((caps = gst_pad_get_current_caps (pad)) == NULL)
463     if ((caps = gst_pad_query_caps (pad, NULL)) == NULL)
464       goto no_caps;
465
466   /* check for raw caps */
467   if (gst_caps_can_intersect (caps, priv->raw_vcaps)) {
468     /* we have raw video caps, insert converter */
469     convert = gst_element_factory_make ("videoconvert", NULL);
470   } else if (gst_caps_can_intersect (caps, priv->raw_acaps)) {
471     /* we have raw audio caps, insert converter */
472     convert = gst_element_factory_make ("audioconvert", NULL);
473   } else {
474     convert = NULL;
475   }
476
477   if (convert) {
478     gst_bin_add (GST_BIN_CAST (element), convert);
479     gst_element_set_state (convert, GST_STATE_PLAYING);
480
481     sinkpad = gst_element_get_static_pad (convert, "sink");
482     gst_pad_link (pad, sinkpad);
483     gst_object_unref (sinkpad);
484
485     /* unref old pad, we reffed before */
486     gst_object_unref (pad);
487
488     /* continue with new pad and caps */
489     pad = gst_element_get_static_pad (convert, "src");
490     if ((caps = gst_pad_get_current_caps (pad)) == NULL)
491       if ((caps = gst_pad_query_caps (pad, NULL)) == NULL)
492         goto no_caps;
493   }
494
495   if (!(factory = find_payloader (urifact, caps)))
496     goto no_factory;
497
498   gst_caps_unref (caps);
499
500   /* we have a payloader now */
501   GST_DEBUG ("found payloader factory %s",
502       gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
503
504   payloader = gst_element_factory_create (factory, NULL);
505   if (payloader == NULL)
506     goto no_payloader;
507
508   g_object_set (payloader, "pt", data->pt, NULL);
509   data->pt++;
510
511   if (g_object_class_find_property (G_OBJECT_GET_CLASS (payloader),
512           "buffer-list"))
513     g_object_set (payloader, "buffer-list", TRUE, NULL);
514
515   /* add the payloader to the pipeline */
516   gst_bin_add (GST_BIN_CAST (element), payloader);
517   gst_element_set_state (payloader, GST_STATE_PLAYING);
518
519   /* link the pad to the sinkpad of the payloader */
520   sinkpad = gst_element_get_static_pad (payloader, "sink");
521   gst_pad_link (pad, sinkpad);
522   gst_object_unref (sinkpad);
523   gst_object_unref (pad);
524
525   /* now expose the srcpad of the payloader as a ghostpad with the same name
526    * as the uridecodebin pad name. */
527   srcpad = gst_element_get_static_pad (payloader, "src");
528   ghostpad = gst_ghost_pad_new (padname, srcpad);
529   gst_object_unref (srcpad);
530   g_free (padname);
531
532   gst_pad_set_active (ghostpad, TRUE);
533   gst_element_add_pad (element, ghostpad);
534
535   return;
536
537   /* ERRORS */
538 no_caps:
539   {
540     GST_WARNING ("could not get caps from pad");
541     g_free (padname);
542     gst_object_unref (pad);
543     return;
544   }
545 no_factory:
546   {
547     GST_DEBUG ("no payloader found");
548     g_free (padname);
549     gst_caps_unref (caps);
550     gst_object_unref (pad);
551     return;
552   }
553 no_payloader:
554   {
555     GST_ERROR ("could not create payloader from factory");
556     g_free (padname);
557     gst_caps_unref (caps);
558     gst_object_unref (pad);
559     return;
560   }
561 }
562
563 static void
564 no_more_pads_cb (GstElement * uribin, GstElement * element)
565 {
566   GST_DEBUG ("no-more-pads");
567   gst_element_no_more_pads (element);
568 }
569
570 static GstElement *
571 rtsp_media_factory_uri_create_element (GstRTSPMediaFactory * factory,
572     const GstRTSPUrl * url)
573 {
574   GstRTSPMediaFactoryURIPrivate *priv;
575   GstElement *topbin, *element, *uribin;
576   GstRTSPMediaFactoryURI *urifact;
577   FactoryData *data;
578
579   urifact = GST_RTSP_MEDIA_FACTORY_URI_CAST (factory);
580   priv = urifact->priv;
581
582   GST_LOG ("creating element");
583
584   topbin = gst_bin_new ("GstRTSPMediaFactoryURI");
585   g_assert (topbin != NULL);
586
587   /* our bin will dynamically expose payloaded pads */
588   element = gst_bin_new ("dynpay0");
589   g_assert (element != NULL);
590
591   uribin = gst_element_factory_make ("uridecodebin", "uribin");
592   if (uribin == NULL)
593     goto no_uridecodebin;
594
595   g_object_set (uribin, "uri", priv->uri, NULL);
596
597   /* keep factory data around */
598   data = g_new0 (FactoryData, 1);
599   data->factory = g_object_ref (factory);
600   data->pt = 96;
601
602   g_object_set_data_full (G_OBJECT (element), factory_key,
603       data, (GDestroyNotify) free_data);
604
605   /* connect to the signals */
606   g_signal_connect (uribin, "autoplug-continue",
607       (GCallback) autoplug_continue_cb, element);
608   g_signal_connect (uribin, "pad-added", (GCallback) pad_added_cb, element);
609   g_signal_connect (uribin, "no-more-pads", (GCallback) no_more_pads_cb,
610       element);
611
612   gst_bin_add (GST_BIN_CAST (element), uribin);
613   gst_bin_add (GST_BIN_CAST (topbin), element);
614
615   return topbin;
616
617 no_uridecodebin:
618   {
619     g_critical ("can't create uridecodebin element");
620     gst_object_unref (element);
621     return NULL;
622   }
623 }