1 /* GStreamer
2  * Copyright (C) <2009> Jan Schmidt <thaytan@noraisin.net>
3  * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <string.h>
26 #include <gst/video/video.h>
27 #include <gst/audio/audio.h>
28 
29 #include "rsndec.h"
30 
31 GST_DEBUG_CATEGORY_STATIC (rsn_dec_debug);
32 #define GST_CAT_DEFAULT rsn_dec_debug
33 
34 static GstStateChangeReturn rsn_dec_change_state (GstElement * element,
35     GstStateChange transition);
36 
37 static void rsn_dec_dispose (GObject * gobj);
38 static void cleanup_child (RsnDec * self);
39 
40 static GstBinClass *rsn_dec_parent_class = NULL;
41 
42 static void
rsn_dec_class_init(RsnDecClass * klass)43 rsn_dec_class_init (RsnDecClass * klass)
44 {
45   GObjectClass *object_class = G_OBJECT_CLASS (klass);
46   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
47 
48   GST_DEBUG_CATEGORY_INIT (rsn_dec_debug, "rsndec",
49       0, "Resin DVD stream decoder");
50 
51   rsn_dec_parent_class = (GstBinClass *) g_type_class_peek_parent (klass);
52   object_class->dispose = rsn_dec_dispose;
53 
54   element_class->change_state = GST_DEBUG_FUNCPTR (rsn_dec_change_state);
55 }
56 
57 static gboolean
rsn_dec_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)58 rsn_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
59 {
60   RsnDec *self = RSN_DEC (parent);
61   gboolean ret = TRUE;
62   const GstStructure *s = gst_event_get_structure (event);
63   const gchar *name = (s ? gst_structure_get_name (s) : NULL);
64 
65   if (name && g_str_equal (name, "application/x-gst-dvd"))
66     ret = gst_pad_push_event (GST_PAD_CAST (self->srcpad), event);
67   else
68     ret = self->sink_event_func (pad, parent, event);
69 
70   return ret;
71 }
72 
73 static void
rsn_dec_init(RsnDec * self,RsnDecClass * klass)74 rsn_dec_init (RsnDec * self, RsnDecClass * klass)
75 {
76   GstPadTemplate *templ;
77 
78   templ =
79       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
80   g_assert (templ != NULL);
81   self->sinkpad =
82       GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("sink",
83           templ));
84   self->sink_event_func = GST_PAD_EVENTFUNC (self->sinkpad);
85   gst_pad_set_event_function (GST_PAD_CAST (self->sinkpad),
86       GST_DEBUG_FUNCPTR (rsn_dec_sink_event));
87 
88   templ = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
89   g_assert (templ != NULL);
90   self->srcpad =
91       GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("src",
92           templ));
93   gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->sinkpad));
94   gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->srcpad));
95 }
96 
97 static void
rsn_dec_dispose(GObject * object)98 rsn_dec_dispose (GObject * object)
99 {
100   RsnDec *self = (RsnDec *) object;
101   cleanup_child (self);
102 
103   G_OBJECT_CLASS (rsn_dec_parent_class)->dispose (object);
104 }
105 
106 static gboolean
rsn_dec_set_child(RsnDec * self,GstElement * new_child)107 rsn_dec_set_child (RsnDec * self, GstElement * new_child)
108 {
109   GstPad *child_pad;
110   if (self->current_decoder) {
111     gst_ghost_pad_set_target (self->srcpad, NULL);
112     gst_ghost_pad_set_target (self->sinkpad, NULL);
113     gst_bin_remove ((GstBin *) self, self->current_decoder);
114     self->current_decoder = NULL;
115   }
116 
117   if (new_child == NULL)
118     return TRUE;
119 
120   if (!gst_bin_add ((GstBin *) self, new_child))
121     return FALSE;
122 
123   child_pad = gst_element_get_static_pad (new_child, "sink");
124   if (child_pad == NULL) {
125     return FALSE;
126   }
127   gst_ghost_pad_set_target (self->sinkpad, child_pad);
128   gst_object_unref (child_pad);
129 
130   child_pad = gst_element_get_static_pad (new_child, "src");
131   if (child_pad == NULL) {
132     return FALSE;
133   }
134   gst_ghost_pad_set_target (self->srcpad, child_pad);
135   gst_object_unref (child_pad);
136 
137   GST_DEBUG_OBJECT (self, "Add child %" GST_PTR_FORMAT, new_child);
138   self->current_decoder = new_child;
139 
140   gst_element_sync_state_with_parent (new_child);
141 
142   return TRUE;
143 }
144 
145 static void
cleanup_child(RsnDec * self)146 cleanup_child (RsnDec * self)
147 {
148   GST_DEBUG_OBJECT (self, "Removing child element");
149   (void) rsn_dec_set_child (self, NULL);
150 }
151 
152 typedef struct
153 {
154   GstCaps *desired_caps;
155   GstCaps *decoder_caps;
156 } RsnDecFactoryFilterCtx;
157 
158 static gboolean
rsndec_factory_filter(GstPluginFeature * feature,RsnDecFactoryFilterCtx * ctx)159 rsndec_factory_filter (GstPluginFeature * feature, RsnDecFactoryFilterCtx * ctx)
160 {
161   GstElementFactory *factory;
162   guint rank;
163   const gchar *klass;
164   const GList *templates;
165   GList *walk;
166   gboolean can_sink = FALSE;
167 
168   /* we only care about element factories */
169   if (!GST_IS_ELEMENT_FACTORY (feature))
170     return FALSE;
171 
172   factory = GST_ELEMENT_FACTORY (feature);
173 
174   klass =
175       gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
176   /* only decoders can play */
177   if (strstr (klass, "Decoder") == NULL)
178     return FALSE;
179 
180   /* only select elements with autoplugging rank */
181   rank = gst_plugin_feature_get_rank (feature);
182   if (rank < GST_RANK_MARGINAL)
183     return FALSE;
184 
185   /* See if the element has a sink pad that can possibly sink this caps */
186 
187   /* get the templates from the element factory */
188   templates = gst_element_factory_get_static_pad_templates (factory);
189   for (walk = (GList *) templates; walk && !can_sink; walk = g_list_next (walk)) {
190     GstStaticPadTemplate *templ = walk->data;
191 
192     /* we only care about the sink templates */
193     if (templ->direction == GST_PAD_SINK) {
194       GstCaps *intersect;
195       GstCaps *tmpl_caps;
196 
197       /* try to intersect the caps with the caps of the template */
198       tmpl_caps = gst_static_caps_get (&templ->static_caps);
199 
200       intersect = gst_caps_intersect (ctx->desired_caps, tmpl_caps);
201       gst_caps_unref (tmpl_caps);
202 
203       /* check if the intersection is empty */
204       if (!gst_caps_is_empty (intersect)) {
205         /* non empty intersection, we can use this element */
206         can_sink = TRUE;
207         ctx->decoder_caps = gst_caps_merge (ctx->decoder_caps, intersect);
208       } else
209         gst_caps_unref (intersect);
210     }
211   }
212 
213   if (can_sink) {
214     GST_DEBUG ("Found decoder element %s (%s)",
215         gst_element_factory_get_metadata (factory,
216             GST_ELEMENT_METADATA_LONGNAME),
217         gst_plugin_feature_get_name (feature));
218   }
219 
220   return can_sink;
221 }
222 
223 static gint
sort_by_ranks(GstPluginFeature * f1,GstPluginFeature * f2)224 sort_by_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
225 {
226   gint diff;
227   const gchar *rname1, *rname2;
228 
229   diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
230   if (diff != 0)
231     return diff;
232 
233   rname1 = gst_plugin_feature_get_name (f1);
234   rname2 = gst_plugin_feature_get_name (f2);
235 
236   diff = strcmp (rname2, rname1);
237 
238   return diff;
239 }
240 
241 static gpointer
_get_decoder_factories(gpointer arg)242 _get_decoder_factories (gpointer arg)
243 {
244   GstElementClass *klass = arg;
245   GList *factories;
246   GstPadTemplate *templ = gst_element_class_get_pad_template (klass,
247       "sink");
248   RsnDecFactoryFilterCtx ctx = { NULL, };
249   GstCaps *raw;
250   gboolean raw_audio;
251   GstRegistry *registry = gst_registry_get ();
252 
253   ctx.desired_caps = gst_pad_template_get_caps (templ);
254 
255   raw =
256       gst_caps_from_string
257       ("audio/x-raw,format=(string){ F32LE, F32BE, F64LE, F64BE }");
258   raw_audio = gst_caps_can_intersect (raw, ctx.desired_caps);
259   if (raw_audio) {
260     GstCaps *sub = gst_caps_subtract (ctx.desired_caps, raw);
261     ctx.desired_caps = sub;
262   } else {
263     gst_caps_ref (ctx.desired_caps);
264   }
265   gst_caps_unref (raw);
266 
267   /* Set decoder caps to empty. Will be filled by the factory_filter */
268   ctx.decoder_caps = gst_caps_new_empty ();
269   GST_DEBUG ("Finding factories for caps: %" GST_PTR_FORMAT, ctx.desired_caps);
270 
271   factories = gst_registry_feature_filter (registry,
272       (GstPluginFeatureFilter) rsndec_factory_filter, FALSE, &ctx);
273 
274   /* If these are audio caps, we add audioconvert, which is not a decoder,
275      but allows raw audio to go through relatively unmolested - this will
276      come handy when we have to send placeholder silence to allow preroll
277      for those DVDs which have titles with no audio track. */
278   if (raw_audio) {
279     GstPluginFeature *feature;
280     GST_DEBUG ("These are audio caps, adding audioconvert");
281     feature =
282         gst_registry_find_feature (registry, "audioconvert",
283         GST_TYPE_ELEMENT_FACTORY);
284     if (feature) {
285       factories = g_list_append (factories, feature);
286     } else {
287       GST_WARNING ("Could not find feature audioconvert");
288     }
289   }
290 
291   factories = g_list_sort (factories, (GCompareFunc) sort_by_ranks);
292 
293   GST_DEBUG ("Available decoder caps %" GST_PTR_FORMAT, ctx.decoder_caps);
294   gst_caps_unref (ctx.decoder_caps);
295   gst_caps_unref (ctx.desired_caps);
296 
297   return factories;
298 }
299 
300 static GstStateChangeReturn
rsn_dec_change_state(GstElement * element,GstStateChange transition)301 rsn_dec_change_state (GstElement * element, GstStateChange transition)
302 {
303   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
304   RsnDec *self = RSN_DEC (element);
305   RsnDecClass *klass = RSN_DEC_GET_CLASS (element);
306 
307   switch (transition) {
308     case GST_STATE_CHANGE_NULL_TO_READY:{
309       GstElement *new_child;
310       const GList *decoder_factories;
311 
312       new_child = gst_element_factory_make ("autoconvert", NULL);
313       decoder_factories = klass->get_decoder_factories (klass);
314       g_object_set (G_OBJECT (new_child), "factories", decoder_factories, NULL);
315       if (new_child == NULL || !rsn_dec_set_child (self, new_child))
316         ret = GST_STATE_CHANGE_FAILURE;
317       break;
318     }
319     case GST_STATE_CHANGE_READY_TO_PAUSED:
320       break;
321     default:
322       break;
323   }
324 
325   if (ret == GST_STATE_CHANGE_FAILURE)
326     return ret;
327   ret =
328       GST_ELEMENT_CLASS (rsn_dec_parent_class)->change_state (element,
329       transition);
330   if (ret == GST_STATE_CHANGE_FAILURE)
331     return ret;
332 
333   switch (transition) {
334     case GST_STATE_CHANGE_PAUSED_TO_READY:
335       break;
336     case GST_STATE_CHANGE_READY_TO_NULL:
337       cleanup_child (self);
338       break;
339     default:
340       break;
341   }
342 
343   return ret;
344 }
345 
346 GType
rsn_dec_get_type(void)347 rsn_dec_get_type (void)
348 {
349   static volatile gsize type = 0;
350 
351   if (g_once_init_enter (&type)) {
352     GType _type;
353     static const GTypeInfo type_info = {
354       sizeof (RsnDecClass),
355       NULL,
356       NULL,
357       (GClassInitFunc) rsn_dec_class_init,
358       NULL,
359       NULL,
360       sizeof (RsnDec),
361       0,
362       (GInstanceInitFunc) rsn_dec_init,
363     };
364 
365     _type = g_type_register_static (GST_TYPE_BIN,
366         "RsnDec", &type_info, G_TYPE_FLAG_ABSTRACT);
367     g_once_init_leave (&type, _type);
368   }
369   return type;
370 }
371 
372 /* Audio decoder subclass */
373 static GstStaticPadTemplate audio_sink_template =
374     GST_STATIC_PAD_TEMPLATE ("sink",
375     GST_PAD_SINK,
376     GST_PAD_ALWAYS,
377     GST_STATIC_CAPS ("audio/mpeg,mpegversion=(int)1;"
378         "audio/x-private1-lpcm;"
379         "audio/x-private1-ac3;" "audio/ac3;" "audio/x-ac3;"
380         "audio/x-private1-dts; audio/x-raw,format=(string)"
381         GST_AUDIO_FORMATS_ALL)
382     );
383 
384 static GstStaticPadTemplate audio_src_template = GST_STATIC_PAD_TEMPLATE ("src",
385     GST_PAD_SRC,
386     GST_PAD_ALWAYS,
387     GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
388     );
389 
390 G_DEFINE_TYPE (RsnAudioDec, rsn_audiodec, RSN_TYPE_DEC);
391 
392 static const GList *
rsn_audiodec_get_decoder_factories(RsnDecClass * klass)393 rsn_audiodec_get_decoder_factories (RsnDecClass * klass)
394 {
395   static GOnce gonce = G_ONCE_INIT;
396 
397   g_once (&gonce, _get_decoder_factories, klass);
398 
399   return (const GList *) gonce.retval;
400 }
401 
402 static void
rsn_audiodec_class_init(RsnAudioDecClass * klass)403 rsn_audiodec_class_init (RsnAudioDecClass * klass)
404 {
405   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
406   RsnDecClass *dec_class = RSN_DEC_CLASS (klass);
407 
408   gst_element_class_add_static_pad_template (element_class,
409       &audio_src_template);
410   gst_element_class_add_static_pad_template (element_class,
411       &audio_sink_template);
412 
413   gst_element_class_set_static_metadata (element_class, "RsnAudioDec",
414       "Audio/Decoder",
415       "Resin DVD audio stream decoder", "Jan Schmidt <thaytan@noraisin.net>");
416 
417   dec_class->get_decoder_factories = rsn_audiodec_get_decoder_factories;
418 }
419 
420 static void
rsn_audiodec_init(RsnAudioDec * self)421 rsn_audiodec_init (RsnAudioDec * self)
422 {
423 }
424 
425 /* Video decoder subclass */
426 static GstStaticPadTemplate video_sink_template =
427 GST_STATIC_PAD_TEMPLATE ("sink",
428     GST_PAD_SINK,
429     GST_PAD_ALWAYS,
430     GST_STATIC_CAPS ("video/mpeg, "
431         "mpegversion = (int) [ 1, 2 ], " "systemstream = (bool) FALSE")
432     );
433 
434 static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE ("src",
435     GST_PAD_SRC,
436     GST_PAD_ALWAYS,
437     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL))
438     );
439 
440 G_DEFINE_TYPE (RsnVideoDec, rsn_videodec, RSN_TYPE_DEC);
441 
442 static const GList *
rsn_videodec_get_decoder_factories(RsnDecClass * klass)443 rsn_videodec_get_decoder_factories (RsnDecClass * klass)
444 {
445   static GOnce gonce = G_ONCE_INIT;
446 
447   g_once (&gonce, _get_decoder_factories, klass);
448 
449   return (const GList *) gonce.retval;
450 }
451 
452 static void
rsn_videodec_class_init(RsnAudioDecClass * klass)453 rsn_videodec_class_init (RsnAudioDecClass * klass)
454 {
455   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
456   RsnDecClass *dec_class = RSN_DEC_CLASS (klass);
457 
458   gst_element_class_add_static_pad_template (element_class,
459       &video_src_template);
460   gst_element_class_add_static_pad_template (element_class,
461       &video_sink_template);
462 
463   gst_element_class_set_static_metadata (element_class, "RsnVideoDec",
464       "Video/Decoder",
465       "Resin DVD video stream decoder", "Jan Schmidt <thaytan@noraisin.net>");
466 
467   dec_class->get_decoder_factories = rsn_videodec_get_decoder_factories;
468 }
469 
470 static void
rsn_videodec_init(RsnVideoDec * self)471 rsn_videodec_init (RsnVideoDec * self)
472 {
473 }
474