New typefind system: bytestream is now part of the core all plugins have been modifie...
[platform/upstream/gstreamer.git] / gst / gsttypefind.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gsttypefind.c: 
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23
24 #include "gst_private.h"
25 #include "gsttype.h"
26 #include "gstinfo.h"
27 #include "gsttypefind.h"
28
29 GstElementDetails gst_type_find_details = {
30   "TypeFind",
31   "Generic",
32   "LGPL",
33   "Finds the media type of a stream",
34   VERSION,
35   "Erik Walthinsen <omega@cse.ogi.edu>,"
36   "Wim Taymans <wim.taymans@chello.be>",
37   "(C) 1999",
38 };
39
40 /* generic templates */
41 GST_PAD_TEMPLATE_FACTORY (type_find_sink_factory,
42   "sink",
43   GST_PAD_SINK,
44   GST_PAD_ALWAYS,
45   NULL
46 );
47
48 /* TypeFind signals and args */
49 enum {
50   HAVE_TYPE,
51   LAST_SIGNAL
52 };
53
54 enum {
55   ARG_0,
56   ARG_CAPS,
57 };
58
59
60 static void     gst_type_find_class_init        (GstTypeFindClass *klass);
61 static void     gst_type_find_init              (GstTypeFind *typefind);
62
63 static void     gst_type_find_set_property      (GObject *object, guint prop_id,
64                                                  const GValue *value, 
65                                                  GParamSpec *pspec);
66 static void     gst_type_find_get_property      (GObject *object, guint prop_id,
67                                                  GValue *value, 
68                                                  GParamSpec *pspec);
69
70 static void     gst_type_find_loopfunc          (GstElement *element);
71 static GstElementStateReturn
72                 gst_type_find_change_state      (GstElement *element);
73
74 static GstElementClass *parent_class = NULL;
75 static guint gst_type_find_signals[LAST_SIGNAL] = { 0 };
76
77 GType
78 gst_type_find_get_type (void)
79 {
80   static GType typefind_type = 0;
81
82   if (!typefind_type) {
83     static const GTypeInfo typefind_info = {
84       sizeof(GstTypeFindClass),
85       NULL,
86       NULL,
87       (GClassInitFunc)gst_type_find_class_init,
88       NULL,
89       NULL,
90       sizeof(GstTypeFind),
91       0,
92       (GInstanceInitFunc)gst_type_find_init,
93       NULL
94     };
95     typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
96                                             "GstTypeFind",
97                                             &typefind_info, 0);
98   }
99   return typefind_type;
100 }
101
102 static void
103 gst_type_find_class_init (GstTypeFindClass *klass)
104 {
105   GObjectClass *gobject_class;
106   GstElementClass *gstelement_class;
107
108   gobject_class = (GObjectClass*)klass;
109   gstelement_class = (GstElementClass*)klass;
110
111   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
112
113   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CAPS,
114     g_param_spec_pointer ("caps", "Caps", "Found capabilities", G_PARAM_READABLE));
115
116   gst_type_find_signals[HAVE_TYPE] =
117       g_signal_new ("have_type", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
118                      G_STRUCT_OFFSET (GstTypeFindClass, have_type), NULL, NULL,
119                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
120                      G_TYPE_POINTER);
121
122   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_set_property);
123   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_get_property);
124
125   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_change_state);
126 }
127
128 static void
129 gst_type_find_init (GstTypeFind *typefind)
130 {
131   typefind->sinkpad = gst_pad_new_from_template (
132                 GST_PAD_TEMPLATE_GET (type_find_sink_factory), "sink");
133   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sinkpad);
134
135   gst_element_set_loop_function (GST_ELEMENT (typefind),
136                                  gst_type_find_loopfunc);
137
138   typefind->caps = NULL;
139 }
140
141 static void
142 gst_type_find_set_property (GObject *object, guint prop_id, 
143                             const GValue *value, GParamSpec *pspec)
144 {
145   GstTypeFind *typefind;
146
147   g_return_if_fail (GST_IS_TYPE_FIND (object));
148
149   typefind = GST_TYPE_FIND (object);
150
151   switch (prop_id) {
152     default:
153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
154       break;
155   }
156 }
157
158 static void
159 gst_type_find_get_property (GObject *object, guint prop_id, 
160                             GValue *value, GParamSpec *pspec)
161 {
162   GstTypeFind *typefind;
163
164   g_return_if_fail (GST_IS_TYPE_FIND (object));
165
166   typefind = GST_TYPE_FIND (object);
167
168   switch (prop_id) {
169     case ARG_CAPS:
170       g_value_set_pointer (value, typefind->caps);
171       break;
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175   }
176 }
177
178 static void
179 gst_type_find_loopfunc (GstElement *element)
180 {
181   GstTypeFind *typefind;
182   const GList *type_list;
183   GstType *type;
184
185   typefind = GST_TYPE_FIND (element);
186
187   GST_DEBUG ("Started typefinding loop in '%s'",
188              GST_OBJECT_NAME (typefind));
189
190   type_list = gst_type_get_list ();
191
192   while (type_list) {
193     GSList *factories;
194     type = (GstType *) type_list->data;
195
196     factories = type->factories;
197
198     while (factories) {
199       GstTypeFactory *factory = GST_TYPE_FACTORY (factories->data);
200       GstTypeFindFunc typefindfunc = (GstTypeFindFunc) factory->typefindfunc;
201       GstCaps *caps;
202
203       GST_CAT_DEBUG (GST_CAT_TYPES, "try type (%p) :%d \"%s\" %p", 
204                  factory, type->id, type->mime, typefindfunc);
205       if (typefindfunc && (caps = typefindfunc (typefind->bs, factory))) {
206         GST_CAT_DEBUG (GST_CAT_TYPES, "found type: %d \"%s\" \"%s\"", 
207                    caps->id, type->mime, gst_caps_get_name (caps));
208         gst_caps_replace (&typefind->caps, caps);
209
210         if (gst_pad_try_set_caps (typefind->sinkpad, caps) <= 0) {
211           g_warning ("typefind: found type but peer didn't accept it");
212         }
213
214         gst_object_ref (GST_OBJECT (typefind));
215         g_signal_emit (G_OBJECT (typefind), gst_type_find_signals[HAVE_TYPE],
216                        0, typefind->caps);
217         gst_object_unref (GST_OBJECT (typefind));
218         return;
219       }
220       factories = g_slist_next (factories);
221     }
222     type_list = g_list_next (type_list);
223   }
224
225   /* if we get here, nothing worked... :'(. */
226   gst_element_error (GST_ELEMENT (typefind), 
227                      "media type could not be detected");
228 }
229
230 static GstElementStateReturn
231 gst_type_find_change_state (GstElement *element)
232 {
233   GstTypeFind *typefind;
234   GstElementStateReturn ret;
235
236   typefind = GST_TYPE_FIND (element);
237
238   switch (GST_STATE_TRANSITION (element)) {
239     case GST_STATE_READY_TO_PAUSED:
240       typefind->bs = gst_bytestream_new (typefind->sinkpad);
241       break;
242     case GST_STATE_PAUSED_TO_READY:
243       gst_bytestream_destroy (typefind->bs);
244       gst_caps_replace (&typefind->caps, NULL);
245       break;
246     default:
247       break;
248   }
249   
250   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
251   
252   return ret;
253 }