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