Merged from INCSCHED on 200505251!!!
[platform/upstream/gstreamer.git] / gst / autoplug / gstautoplugger.c
1 /* GStreamer
2  * Copyright (C) 2001 RidgeRun, Inc. (www.ridgerun.com)
3  *
4  * gstautoplugger.c: Data  for the dynamic autopluggerger
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <gst/gst.h>
23
24 GstElementDetails gst_autoplugger_details = {
25   "Dynamic autoplugger",
26   "Autoplugger",
27   "Magic element that converts from any type to any other",
28   VERSION,
29   "Erik Walthinsen <omega@temple-baptist.com>",
30   "(C) 2001 RidgeRun, Inc. (www.ridgerun.com)",
31 };
32
33 #define GST_TYPE_AUTOPLUGGER \
34   (gst_autoplugger_get_type())
35 #define GST_AUTOPLUGGER(obj) \
36   (GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUGGER,GstAutoplugger))
37 #define GST_AUTOPLUGGER_CLASS(klass) \
38   (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_AUTOPLUGGER,GstAutopluggerClass))
39 #define GST_IS_AUTOPLUGGER(obj) \
40   (GTK_CHECK_TYPE((obj),GST_TYPE_AUTOPLUGGER))
41 #define GST_IS_AUTOPLUGGER_CLASS(obj) \
42   (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_AUTOPLUGGER))
43
44 typedef struct _GstAutoplugger GstAutoplugger;
45 typedef struct _GstAutopluggerClass GstAutopluggerClass;
46
47 struct _GstAutoplugger {
48   GstBin bin;
49   gint paused;
50
51   GstElement *cache;
52   gboolean cache_first_buffer;
53   GstPad *cache_sinkpad, *cache_srcpad;
54
55   GstElement *typefind;
56   GstPad *typefind_sinkpad;
57
58   GstPad *sinkpadpeer, *srcpadpeer;
59   GstCaps *sinkcaps, *srccaps;
60
61   GstCaps *sinktemplatecaps;
62
63   GstAutoplug *autoplug;
64   GstElement *autobin;
65
66   gboolean disable_nocaps;
67 };
68
69 struct _GstAutopluggerClass {
70   GstBinClass parent_class;
71 };
72
73
74 /*  signals and args */
75 enum {
76   LAST_SIGNAL
77 };
78
79 enum {
80   ARG_0,
81 };
82
83
84 static void                     gst_autoplugger_class_init      (GstAutopluggerClass *klass);
85 static void                     gst_autoplugger_init            (GstAutoplugger *queue);
86
87 static void                     gst_autoplugger_set_arg         (GtkObject *object, GtkArg *arg, guint id);
88 static void                     gst_autoplugger_get_arg         (GtkObject *object, GtkArg *arg, guint id);
89
90 //static GstElementStateReturn  gst_autoplugger_change_state    (GstElement *element);
91
92
93 static void     gst_autoplugger_external_sink_caps_changed      (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
94 static void     gst_autoplugger_external_src_caps_changed       (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
95 static void     gst_autoplugger_external_sink_caps_nego_failed  (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
96 static void     gst_autoplugger_external_src_caps_nego_failed   (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
97 static void     gst_autoplugger_external_sink_connected         (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
98 static void     gst_autoplugger_external_src_connected          (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
99
100 static void     gst_autoplugger_cache_first_buffer              (GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger);
101 static void     gst_autoplugger_cache_empty                     (GstElement *element, GstAutoplugger *autoplugger);
102 static void     gst_autoplugger_typefind_have_type              (GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger);
103
104 static GstElementClass *parent_class = NULL;
105 //static guint gst_autoplugger_signals[LAST_SIGNAL] = { 0 };
106
107 GtkType
108 gst_autoplugger_get_type(void) {
109   static GtkType autoplugger_type = 0;
110
111   if (!autoplugger_type) {
112     static const GtkTypeInfo autoplugger_info = {
113       "GstAutoplugger",
114       sizeof(GstAutoplugger),
115       sizeof(GstAutopluggerClass),
116       (GtkClassInitFunc)gst_autoplugger_class_init,
117       (GtkObjectInitFunc)gst_autoplugger_init,
118       (GtkArgSetFunc)gst_autoplugger_set_arg,
119       (GtkArgGetFunc)gst_autoplugger_get_arg,
120       (GtkClassInitFunc)NULL,
121     };
122     autoplugger_type = gtk_type_unique (GST_TYPE_BIN, &autoplugger_info);
123   }
124   return autoplugger_type;
125 }
126
127 static void
128 gst_autoplugger_class_init (GstAutopluggerClass *klass)
129 {
130   GtkObjectClass *gtkobject_class;
131   GstElementClass *gstelement_class;
132
133   gtkobject_class = (GtkObjectClass*)klass;
134   gstelement_class = (GstElementClass*)klass;
135
136   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
137
138 /*
139   gst_autoplugger_signals[_EMPTY] =
140     gtk_signal_new ("_empty", GTK_RUN_LAST, gtkobject_class->type,
141                     GTK_SIGNAL_OFFSET (GstAutopluggerClass, _empty),
142                     gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
143   gtk_object_class_add_signals (gtkobject_class, gst_autoplugger_signals, LAST_SIGNAL);
144 */
145
146 /*
147   gtk_object_add_arg_type ("GstAutoplugger::buffer_count", GTK_TYPE_INT,
148                            GTK_ARG_READABLE, ARG_BUFFER_COUNT);
149   gtk_object_add_arg_type ("GstAutoplugger::reset", GTK_TYPE_BOOL,
150                            GTK_ARG_WRITABLE, ARG_RESET);
151 */
152
153   gtkobject_class->set_arg = gst_autoplugger_set_arg;
154   gtkobject_class->get_arg = gst_autoplugger_get_arg;
155
156 //  gstelement_class->change_state = gst_autoplugger_change_state;
157 }
158
159 static void
160 gst_autoplugger_init (GstAutoplugger *autoplugger)
161 {
162   // create the autoplugger cache, which is the fundamental unit of the autopluggerger
163   // FIXME we need to find a way to set element's name before _init
164   // FIXME ... so we can name the subelements uniquely
165   autoplugger->cache = gst_elementfactory_make("autoplugcache", "unnamed_autoplugcache");
166   g_return_if_fail (autoplugger->cache != NULL);
167
168   GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
169   gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
170
171   // attach signals to the cache
172   gtk_signal_connect (GTK_OBJECT (autoplugger->cache), "first_buffer",
173                       GTK_SIGNAL_FUNC (gst_autoplugger_cache_first_buffer), autoplugger);
174
175   // add the cache to self
176   gst_bin_add (GST_BIN(autoplugger), autoplugger->cache);
177
178   // get the cache's pads so we can attach stuff to them
179   autoplugger->cache_sinkpad = gst_element_get_pad (autoplugger->cache, "sink");
180   autoplugger->cache_srcpad = gst_element_get_pad (autoplugger->cache, "src");
181
182   // attach handlers to the typefind pads
183   gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_changed",
184                       GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_changed), autoplugger);
185   gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_changed",
186                       GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_changed), autoplugger);
187   gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_nego_failed",
188                       GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_nego_failed), autoplugger);
189   gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_nego_failed",
190                       GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_nego_failed), autoplugger);
191 //  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "connected",
192 //                      GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_connected), autoplugger);
193 //  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "connected",
194 //                      GTK_SIGNAL_FUNC (gst_autoplugger_external_src_connected), autoplugger);
195
196   // ghost both of these pads to the outside world
197   gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_sinkpad, "sink");
198   gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_srcpad, "src");
199 }
200
201
202 static void
203 gst_autoplugger_external_sink_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
204 {
205   GstPadTemplate *peertemplate;
206   GstCaps *peercaps, *peertemplatecaps;
207
208   GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink connected");
209 //  autoplugger->sinkpadpeer = peerpad;
210
211   if (autoplugger->sinkpadpeer) {
212     peercaps = GST_PAD_CAPS(autoplugger->sinkpadpeer);
213     if (peercaps)
214       GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
215                gst_caps_get_mime(peercaps));
216     peertemplate = GST_PAD_PADTEMPLATE(autoplugger->sinkpadpeer);
217     if (peertemplate) {
218       peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
219       if (peertemplatecaps) {
220         GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
221                  gst_caps_get_mime(peertemplatecaps));
222       }
223     }
224   }
225 }
226
227 static void
228 gst_autoplugger_external_src_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
229 {
230   GstPadTemplate *peertemplate;
231   GstCaps *peercaps, *peertemplatecaps;
232
233   GST_INFO(GST_CAT_AUTOPLUG, "have cache:src connected");
234 //  autoplugger->srcpadpeer = peerpad;
235
236   if (autoplugger->srcpadpeer) {
237     peercaps = GST_PAD_CAPS(autoplugger->srcpadpeer);
238     if (peercaps)
239       GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
240                gst_caps_get_mime(peercaps));
241     peertemplate = GST_PAD_PADTEMPLATE(autoplugger->srcpadpeer);
242     if (peertemplate) {
243       peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
244       if (peertemplatecaps) {
245         GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
246                  gst_caps_get_mime(peertemplatecaps));
247         autoplugger->sinktemplatecaps = peertemplatecaps;
248 //        GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
249 //        gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
250       }
251     }
252   }
253 }
254
255
256 static void
257 gst_autoplugger_external_sink_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
258 {
259   GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink caps of %s\n",gst_caps_get_mime(caps));
260   autoplugger->sinkcaps = caps;
261 }
262
263 static void
264 gst_autoplugger_external_src_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
265 {
266   GST_INFO(GST_CAT_AUTOPLUG, "have cache:src caps of %s\n",gst_caps_get_mime(caps));
267   autoplugger->srccaps = caps;
268 }
269
270
271 static gboolean
272 gst_autoplugger_autoplug(GstAutoplugger *autoplugger,GstPad *srcpad,GstCaps *srccaps,GstCaps *sinkcaps)
273 {
274   GstPad *sinkpad;
275
276   sinkpad = GST_PAD(GST_PAD_PEER(srcpad));
277   GST_DEBUG(GST_CAT_AUTOPLUG,"disconnecting %s:%s and %s:%s to autoplug between them\n",
278             GST_DEBUG_PAD_NAME(srcpad),GST_DEBUG_PAD_NAME(sinkpad));
279   GST_DEBUG(GST_CAT_AUTOPLUG,"srcpadcaps are of type %s\n",gst_caps_get_mime(srccaps));
280   GST_DEBUG(GST_CAT_AUTOPLUG,"sinkpadcaps are of type %s\n",gst_caps_get_mime(sinkcaps));
281
282   // disconnect the pads
283   GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting the pads that will be joined by an autobin\n");
284   gst_pad_disconnect(srcpad,sinkpad);
285
286   if (!autoplugger->autoplug) {
287     autoplugger->autoplug = gst_autoplugfactory_make("static");
288     g_return_val_if_fail(autoplugger->autoplug != NULL, FALSE);
289   }
290   GST_DEBUG(GST_CAT_AUTOPLUG, "building autoplugged bin between caps\n");
291   autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
292     srccaps,sinkcaps,NULL);
293   g_return_val_if_fail(autoplugger->autobin != NULL, FALSE);
294   gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
295
296 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
297
298   // FIXME this is a hack
299 //  GST_DEBUG(GST_CAT_AUTOPLUG, "copying failed caps to srcpad %s:%s to ensure renego\n",GST_DEBUG_PAD_NAME(autoplugger->cache_srcpad));
300 //  gst_pad_set_caps(srcpad,srccaps);
301
302   if (GST_PAD_CAPS(srcpad) == NULL) GST_DEBUG(GST_CAT_AUTOPLUG,"no caps on cache:src!\n");
303
304   // attach the autoplugged bin
305   GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between the two pads\n");
306   gst_pad_connect(srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
307 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
308   gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),sinkpad);
309 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
310
311   // FIXME try to force the renego
312 //  GST_DEBUG(GST_CAT_AUTOPLUG, "trying to force everyone to nego\n");
313 //  gst_pad_renegotiate(gst_element_get_pad(autoplugger->autobin,"sink"));
314 //  gst_pad_renegotiate(sinkpad);
315
316   return TRUE;
317 }
318
319 static void
320 gst_autoplugger_external_sink_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
321 {
322   GstPad *srcpad_peer;
323   GstPadTemplate *srcpad_peer_template;
324   GstCaps *srcpad_peer_caps;
325   GstPad *sinkpad_peer;
326   GstCaps *sinkpad_peer_caps;
327
328   GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on sinkpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
329
330   autoplugger->paused++;
331   if (autoplugger->paused == 1)
332     // try to PAUSE the whole thing
333     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
334
335   srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
336   g_return_if_fail(srcpad_peer != NULL);
337   srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
338   g_return_if_fail(srcpad_peer_template != NULL);
339   srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
340   g_return_if_fail(srcpad_peer_caps != NULL);
341
342   sinkpad_peer = GST_PAD(GST_PAD_PEER(pad));
343   g_return_if_fail(sinkpad_peer != NULL);
344   sinkpad_peer_caps = GST_PAD_CAPS(sinkpad_peer);
345   g_return_if_fail(sinkpad_peer_caps != NULL);
346
347   if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,sinkpad_peer_caps,srcpad_peer_caps))
348     *result = TRUE;
349
350   // force renego
351   gst_pad_renegotiate(GST_PAD(GST_PAD_PEER(autoplugger->cache_sinkpad)));
352
353   autoplugger->paused--;
354   if (autoplugger->paused == 0)
355     // try to PLAY the whole thing
356     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
357
358   GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on sinkpad %s:%s",GST_DEBUG_PAD_NAME(pad));
359 }
360
361 static void
362 gst_autoplugger_external_src_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
363 {
364   GstCaps *srcpad_caps;
365   GstPad *srcpad_peer;
366   GstPadTemplate *srcpad_peer_template;
367   GstCaps *srcpad_peer_caps;
368
369   GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on srcpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
370
371   autoplugger->paused++;
372   if (autoplugger->paused == 1)
373     // try to PAUSE the whole thing
374     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
375
376   srcpad_caps = GST_PAD_CAPS(autoplugger->cache_srcpad);
377
378   srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
379   g_return_if_fail(srcpad_peer != NULL);
380   srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
381   g_return_if_fail(srcpad_peer_template != NULL);
382   srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
383   g_return_if_fail(srcpad_peer_caps != NULL);
384
385   if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,srcpad_caps,srcpad_peer_caps))
386     *result = TRUE;
387
388   autoplugger->paused--;
389   if (autoplugger->paused == 0)
390     // try to PLAY the whole thing
391     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
392
393   autoplugger->disable_nocaps = TRUE;
394
395   GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on srcpad %s:%s",GST_DEBUG_PAD_NAME(pad));
396 }
397
398
399 static void
400 gst_autoplugger_cache_empty(GstElement *element, GstAutoplugger *autoplugger)
401 {
402   GstPad *cache_sinkpad_peer,*cache_srcpad_peer;
403
404   GST_INFO(GST_CAT_AUTOPLUG, "autoplugger cache has hit empty, we can now remove it");
405
406   autoplugger->paused++;
407   if (autoplugger->paused == 1)
408     // try to PAUSE the whole thing
409     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
410
411   // disconnect the cache from its peers
412   GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting autoplugcache from its peers\n");
413   cache_sinkpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_sinkpad));
414   cache_srcpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_srcpad));
415   gst_pad_disconnect(cache_sinkpad_peer,autoplugger->cache_sinkpad);
416   gst_pad_disconnect(autoplugger->cache_srcpad,cache_srcpad_peer);
417
418   // remove the cache from self
419   GST_DEBUG(GST_CAT_AUTOPLUG, "removing the cache from the autoplugger\n");
420   gst_bin_remove (GST_BIN(autoplugger), autoplugger->cache);
421
422   // connect the two pads
423   GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the autoplugcache's former peers\n");
424   gst_pad_connect(cache_sinkpad_peer,cache_srcpad_peer);
425
426   autoplugger->paused--;
427   if (autoplugger->paused == 0)
428     // try to PLAY the whole thing
429     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
430
431   xmlSaveFile("autoplugger.gst", gst_xml_write(GST_ELEMENT_SCHED(autoplugger)->parent));
432
433   GST_INFO(GST_CAT_AUTOPLUG, "autoplugger_cache_empty finished");
434 }
435
436 static void
437 gst_autoplugger_typefind_have_type(GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger) 
438 {
439   GST_INFO(GST_CAT_AUTOPLUG, "typefind claims to have a type: %s",gst_caps_get_mime(caps));
440
441 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
442
443   autoplugger->paused++;
444   if (autoplugger->paused == 1)
445     // try to PAUSE the whole thing
446     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
447
448   // first disconnect the typefind and shut it down
449   GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting typefind from the cache\n");
450   gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
451   gst_bin_remove(GST_BIN(autoplugger),autoplugger->typefind);
452
453   // FIXME FIXME now we'd compare caps and see if we need to autoplug something in the middle, but for 
454   // now we're going to just reconnect where we left off
455   // FIXME FIXME FIXME!!!: this should really be done in the caps failure!!!
456 /*
457   if (!autoplugger->autoplug) {
458     autoplugger->autoplug = gst_autoplugfactory_make("static");
459   }
460   autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
461       caps,autoplugger->sinktemplatecaps,NULL);
462   g_return_if_fail(autoplugger->autobin != NULL);
463   gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
464
465 //  // re-attach the srcpad's original peer to the cache
466 //  GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the cache to the downstream peer\n");
467 //  gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
468
469   // attach the autoplugged bin
470   GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between cache and downstream peer\n");
471   gst_pad_connect(autoplugger->cache_srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
472   gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),autoplugger->srcpadpeer);
473 */
474
475   // FIXME set the caps on the new connection
476 //  GST_DEBUG(GST_CAT_AUTOPLUG,"forcing caps on the typefound pad\n");
477 //  gst_pad_set_caps(autoplugger->cache_srcpad,caps);
478
479   // reattach the original outside srcpad
480   GST_DEBUG(GST_CAT_AUTOPLUG,"re-attaching downstream peer to autoplugcache\n");
481   gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
482
483   // now reset the autoplugcache
484   GST_DEBUG(GST_CAT_AUTOPLUG, "resetting the cache to send first buffer(s) again\n");
485   gtk_object_set(GTK_OBJECT(autoplugger->cache),"reset",TRUE,NULL);
486
487   // attach the cache_empty handler
488   // FIXME this is the wrong place, it shouldn't be done until we get successful caps nego!
489   gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
490                      GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);
491
492   autoplugger->paused--;
493   if (autoplugger->paused == 0)
494     // try to PLAY the whole thing
495     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
496
497   GST_INFO(GST_CAT_AUTOPLUG, "typefind_have_type finished");
498 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
499 }
500
501 static void
502 gst_autoplugger_cache_first_buffer(GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger)
503 {
504   GST_INFO(GST_CAT_AUTOPLUG, "have first buffer through cache");
505   autoplugger->cache_first_buffer = TRUE;
506
507   // if there are no established caps, worry
508   if (!autoplugger->sinkcaps) {
509     GST_INFO(GST_CAT_AUTOPLUG, "have no caps for the buffer, Danger Will Robinson!");
510
511 if (autoplugger->disable_nocaps) {
512   GST_DEBUG(GST_CAT_AUTOPLUG, "not dealing with lack of caps this time\n");
513   return;
514 }
515
516 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
517
518   autoplugger->paused++;
519   if (autoplugger->paused == 1)
520     // try to PAUSE the whole thing
521     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
522
523     // detach the srcpad
524     GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting cache from its downstream peer\n");
525     autoplugger->srcpadpeer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
526     gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
527
528     // instantiate the typefind and set up the signal handlers
529     if (!autoplugger->typefind) {
530       GST_DEBUG(GST_CAT_AUTOPLUG, "creating typefind and setting signal handler\n");
531       autoplugger->typefind = gst_elementfactory_make("typefind","unnamed_typefind");
532       autoplugger->typefind_sinkpad = gst_element_get_pad(autoplugger->typefind,"sink");
533       gtk_signal_connect(GTK_OBJECT(autoplugger->typefind),"have_type",
534                          GTK_SIGNAL_FUNC (gst_autoplugger_typefind_have_type), autoplugger);
535     }
536     // add it to self and attach it
537     GST_DEBUG(GST_CAT_AUTOPLUG, "adding typefind to self and connecting to cache\n");
538     gst_bin_add(GST_BIN(autoplugger),autoplugger->typefind);
539     gst_pad_connect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
540
541     // bring the typefind into playing state
542     GST_DEBUG(GST_CAT_AUTOPLUG, "setting typefind state to PLAYING\n");
543     gst_element_set_state(autoplugger->cache,GST_STATE_PLAYING);
544
545   autoplugger->paused--;
546   if (autoplugger->paused == 0)
547     // try to PLAY the whole thing
548     gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
549
550     GST_INFO(GST_CAT_AUTOPLUG,"here we go into nothingness, hoping the typefind will return us to safety");
551 gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
552   } else {
553 //    // attach the cache_empty handler, since the cache simply isn't needed
554 //    gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
555 //                       GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);  
556   }
557 }
558
559 static void
560 gst_autoplugger_set_arg (GtkObject *object, GtkArg *arg, guint id)
561 {
562   GstAutoplugger *autoplugger;
563
564   autoplugger = GST_AUTOPLUGGER (object);
565
566   switch (id) {
567     default:
568       break;
569   }
570 }
571
572 static void
573 gst_autoplugger_get_arg (GtkObject *object, GtkArg *arg, guint id)
574 {
575   GstAutoplugger *autoplugger;
576
577   autoplugger = GST_AUTOPLUGGER (object);
578
579   switch (id) {
580     default:
581       arg->type = GTK_TYPE_INVALID;
582       break;
583   }
584 }
585
586 static gboolean
587 plugin_init (GModule *module, GstPlugin *plugin)
588 {
589   GstElementFactory *factory;
590
591   factory = gst_elementfactory_new ("autoplugger", GST_TYPE_AUTOPLUGGER,
592                                     &gst_autoplugger_details);
593   g_return_val_if_fail (factory != NULL, FALSE);
594
595   gst_plugin_add_factory (plugin, factory);
596
597   return TRUE;
598 }
599
600 GstPluginDesc plugin_desc = {
601   GST_VERSION_MAJOR,
602   GST_VERSION_MINOR,
603   "autoplugger",
604   plugin_init
605 };
606