Raw and crude port of decodebin.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 12 Apr 2005 10:48:58 +0000 (10:48 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 12 Apr 2005 10:48:58 +0000 (10:48 +0000)
Original commit message from CVS:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
(compare_ranks), (print_feature), (gst_decode_bin_init),
(dynamic_create), (dynamic_free), (find_compatibles),
(mimetype_is_raw), (close_pad_link), (got_redirect),
(try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
(new_pad), (no_more_pads), (unlinked), (close_link), (type_found),
(gst_decode_bin_change_state):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
(gst_play_base_bin_init), (group_destroy), (group_commit),
(check_queue), (queue_overrun), (queue_threshold_reached),
(queue_out_of_data), (gen_preroll_element), (unknown_type),
(new_decoded_pad), (setup_subtitle), (gen_source_element),
(got_redirect), (setup_source), (play_base_eos),
(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
(gst_play_base_bin_remove_element):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
(gst_play_bin_init), (gst_play_bin_dispose),
(gst_play_bin_set_property), (gen_video_element),
(gen_text_element), (gen_audio_element), (remove_sinks),
(gst_play_bin_send_event):
* gst/playback/gststreaminfo.c: (gst_stream_info_dispose),
(stream_info_change_state), (gst_stream_info_set_mute):
* gst/playback/gststreamselector.c: (gst_stream_selector_init),
(gst_stream_selector_get_caps), (gst_stream_selector_setcaps),
(gst_stream_selector_request_new_pad), (gst_stream_selector_event),
(gst_stream_selector_chain):
* gst/playback/test.c: (gen_video_element), (gen_audio_element),
(main):
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps),
(gst_xvimagesink_setcaps), (gst_xvimagesink_get_times),
(gst_xvimagesink_show_frame), (gst_xvimagesink_chain),
(gst_xvimagesink_buffer_alloc), (gst_xvimagesink_class_init):
Raw and crude port of decodebin.
Make playbin compile.

ChangeLog
gst/playback/README
gst/playback/gstdecodebin.c
gst/playback/gstplaybasebin.c
gst/playback/gstplaybasebin.h
gst/playback/gstplaybin.c
gst/playback/gststreaminfo.c
gst/playback/gststreamselector.c
gst/playback/test.c
sys/xvimage/xvimagesink.c

index 29b2ecc..5287ef1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2005-04-12  Wim Taymans  <wim@fluendo.com>
+
+       * gst/playback/README:
+       * gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
+       (compare_ranks), (print_feature), (gst_decode_bin_init),
+       (dynamic_create), (dynamic_free), (find_compatibles),
+       (mimetype_is_raw), (close_pad_link), (got_redirect),
+       (try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
+       (new_pad), (no_more_pads), (unlinked), (close_link), (type_found),
+       (gst_decode_bin_change_state):
+       * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
+       (gst_play_base_bin_init), (group_destroy), (group_commit),
+       (check_queue), (queue_overrun), (queue_threshold_reached),
+       (queue_out_of_data), (gen_preroll_element), (unknown_type),
+       (new_decoded_pad), (setup_subtitle), (gen_source_element),
+       (got_redirect), (setup_source), (play_base_eos),
+       (gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
+       (gst_play_base_bin_remove_element):
+       * gst/playback/gstplaybasebin.h:
+       * gst/playback/gstplaybin.c: (gst_play_bin_class_init),
+       (gst_play_bin_init), (gst_play_bin_dispose),
+       (gst_play_bin_set_property), (gen_video_element),
+       (gen_text_element), (gen_audio_element), (remove_sinks),
+       (gst_play_bin_send_event):
+       * gst/playback/gststreaminfo.c: (gst_stream_info_dispose),
+       (stream_info_change_state), (gst_stream_info_set_mute):
+       * gst/playback/gststreamselector.c: (gst_stream_selector_init),
+       (gst_stream_selector_get_caps), (gst_stream_selector_setcaps),
+       (gst_stream_selector_request_new_pad), (gst_stream_selector_event),
+       (gst_stream_selector_chain):
+       * gst/playback/test.c: (gen_video_element), (gen_audio_element),
+       (main):
+       * sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps),
+       (gst_xvimagesink_setcaps), (gst_xvimagesink_get_times),
+       (gst_xvimagesink_show_frame), (gst_xvimagesink_chain),
+       (gst_xvimagesink_buffer_alloc), (gst_xvimagesink_class_init):
+       Raw and crude port of decodebin. 
+       Make playbin compile.
+
 2005-04-06  Wim Taymans  <wim@fluendo.com>
 
        * ext/gnomevfs/Makefile.am:
index 5726a1a..3a50371 100644 (file)
@@ -12,6 +12,27 @@ decoderbin:
    - threading after demuxing?
    - new_media events should be handled.
    - caching of elements.
+   - abstract more elements, pads (typefind, ...);
+
+   The autoplugging happens as follows:
+
+   1) typefind is added internally to the bin.
+   2) the have_type signal is connected to typefind.
+   3) in the have_type callback the close_pad_link function is called
+   4) close_pad_link checks the type on the pad, if it is raw, a ghostpad
+      is created and autoplugging for that pad stops.
+   5) if the type of the pad is not raw, a list of possible elements that
+      can connect to this type is generated in find_compatibles.
+   6) try_to_link_1 with the element list is called. The function will loop
+      over the element list and will try to connect one of the elements to
+      the pad. If the link works, a call is made to close_link.
+   7) close_link loops over all the source pads of the element and 
+      recursively calls 4) for any ALWAYS pad. For elements with
+      a SOMETIMES pad, a structure is set up and is passed to the callback
+      of the new_pad signal.
+   8) in the new_pad callback, 4) is called to try to autoplug the
+      new pad.
+
 
 playbasebin:
 
index e7e680e..33a7409 100644 (file)
@@ -78,8 +78,12 @@ struct _GstDecodeBinClass
   void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
   /* signal fired when we found a pad that we cannot decode */
   void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
+  /* signal fired when we got a redirect attempt */
+  void (*got_redirect) (GstElement * element, const gchar * new_location);
 };
 
+#define DEFAULT_THREADED       FALSE
+
 /* props */
 enum
 {
@@ -93,6 +97,7 @@ enum
   SIGNAL_NEW_DECODED_PAD,
   SIGNAL_REMOVED_DECODED_PAD,
   SIGNAL_UNKNOWN_TYPE,
+  SIGNAL_REDIRECT,
   LAST_SIGNAL
 };
 
@@ -127,6 +132,8 @@ static void close_pad_link (GstElement * element, GstPad * pad,
     GstCaps * caps, GstDecodeBin * decode_bin, gboolean more);
 static void unlinked (GstPad * pad, GstPad * peerpad,
     GstDecodeBin * decode_bin);
+static void new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic);
+static void no_more_pads (GstElement * element, GstDynamic * dynamic);
 
 static GstElementClass *parent_class;
 static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
@@ -184,7 +191,7 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
 
   g_object_class_install_property (gobject_klass, ARG_THREADED,
       g_param_spec_boolean ("threaded", "Threaded", "Use threads",
-          FALSE, G_PARAM_READWRITE));
+          DEFAULT_THREADED, G_PARAM_READWRITE));
 
   gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
       g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
@@ -202,6 +209,11 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
       NULL, NULL, gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2,
       GST_TYPE_PAD, GST_TYPE_CAPS);
+  gst_decode_bin_signals[SIGNAL_REDIRECT] =
+      g_signal_new ("got-redirect", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, got_redirect),
+      NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1,
+      G_TYPE_STRING);
 
   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
 
@@ -260,18 +272,28 @@ static gint
 compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
 {
   gint diff;
+  const gchar *rname1, *rname2;
 
   diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
   if (diff != 0)
     return diff;
-  return strcmp (gst_plugin_feature_get_name (f2),
-      gst_plugin_feature_get_name (f1));
+
+  rname1 = gst_plugin_feature_get_name (f1);
+  rname2 = gst_plugin_feature_get_name (f2);
+
+  diff = strcmp (rname2, rname1);
+
+  return diff;
 }
 
 static void
 print_feature (GstPluginFeature * feature)
 {
-  GST_DEBUG ("%s", gst_plugin_feature_get_name (feature));
+  const gchar *rname;
+
+  rname = gst_plugin_feature_get_name (feature);
+
+  GST_DEBUG ("%s", rname);
 }
 
 static void
@@ -307,6 +329,7 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
         G_CALLBACK (type_found), decode_bin);
   }
 
+  decode_bin->threaded = DEFAULT_THREADED;
   decode_bin->dynamics = NULL;
 }
 
@@ -338,6 +361,40 @@ gst_decode_bin_dispose (GObject * object)
   }
 }
 
+static GstDynamic *
+dynamic_create (GstElement * element, GstDecodeBin * decode_bin)
+{
+  GstDynamic *dyn;
+
+  /* take refs */
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_ref (GST_OBJECT (decode_bin));
+
+  dyn = g_new0 (GstDynamic, 1);
+  dyn->element = element;
+  dyn->decode_bin = decode_bin;
+  dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
+      G_CALLBACK (new_pad), dyn);
+  dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
+      G_CALLBACK (no_more_pads), dyn);
+
+  return dyn;
+}
+
+static void
+dynamic_free (GstDynamic * dyn)
+{
+  /* disconnect signals */
+  g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->np_sig_id);
+  g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->nmp_sig_id);
+
+  gst_object_unref (GST_OBJECT (dyn->element));
+  gst_object_unref (GST_OBJECT (dyn->decode_bin));
+  dyn->element = NULL;
+  dyn->decode_bin = NULL;
+  g_free (dyn);
+}
+
 /* this function runs through the element factories and returns a list
  * of all elements that are able to sink the given caps 
  */
@@ -369,17 +426,27 @@ find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
         /* check if the intersection is empty */
         if (!gst_caps_is_empty (intersect)) {
           /* non empty intersection, we can use this element */
-          to_try = g_list_append (to_try, factory);
-          gst_caps_free (intersect);
+          to_try = g_list_prepend (to_try, factory);
+          gst_caps_unref (intersect);
           break;
         }
-        gst_caps_free (intersect);
+        gst_caps_unref (intersect);
       }
     }
   }
+  to_try = g_list_reverse (to_try);
+
   return to_try;
 }
 
+static gboolean
+mimetype_is_raw (const gchar * mimetype)
+{
+  return g_str_has_prefix (mimetype, "video/x-raw") ||
+      g_str_has_prefix (mimetype, "audio/x-raw") ||
+      g_str_has_prefix (mimetype, "text/plain");
+}
+
 /* given a pad and a caps from an element, find the list of elements
  * that could connect to the pad
  *
@@ -393,26 +460,28 @@ static void
 close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
     GstDecodeBin * decode_bin, gboolean more)
 {
-  GList *to_try;
   GstStructure *structure;
   const gchar *mimetype;
+  gchar *padname;
+  gint diff;
 
-  if (!strncmp (gst_pad_get_name (pad), "current_", 8))
+  padname = gst_pad_get_name (pad);
+  diff = strncmp (padname, "current_", 8);
+  g_free (padname);
+
+  /* hack.. ignore current pads */
+  if (!diff)
     return;
 
   /* the caps is empty, this means the pad has no type, we can only
    * decide to fire the unknown_type signal. */
-  if (caps == NULL || gst_caps_is_empty (caps)) {
-    g_signal_emit (G_OBJECT (decode_bin),
-        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
-    return;
-  }
+  if (caps == NULL || gst_caps_is_empty (caps))
+    goto unknown_type;
 
   /* the caps is any, this means the pad can be anything and
    * we don't know yet */
-  if (gst_caps_is_any (caps)) {
-    return;
-  }
+  if (gst_caps_is_any (caps))
+    goto dont_know_yet;
 
   GST_LOG_OBJECT (element, "trying to close %" GST_PTR_FORMAT, caps);
 
@@ -424,9 +493,7 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
 
   /* first see if this is raw. If the type is raw, we can
    * create a ghostpad for this pad. */
-  if (g_str_has_prefix (mimetype, "video/x-raw") ||
-      g_str_has_prefix (mimetype, "audio/x-raw") ||
-      g_str_has_prefix (mimetype, "text/plain")) {
+  if (mimetype_is_raw (mimetype)) {
     gchar *padname;
     GstPad *ghost;
 
@@ -444,27 +511,62 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
         gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost, !more);
 
     g_free (padname);
-    return;
-  }
+  } else {
+    GList *to_try;
+
+    /* if the caps has many types, we need to delay */
+    if (gst_caps_get_size (caps) != 1)
+      goto many_types;
 
-  if (gst_caps_get_size (caps) == 1) {
-    /* then continue plugging, first find all compatible elements */
+    /* continue plugging, first find all compatible elements */
     to_try = find_compatibles (decode_bin, caps);
-    if (to_try == NULL) {
-      /* no compatible elements, fire the unknown_type signal, we cannot go
-       * on */
-      g_signal_emit (G_OBJECT (decode_bin),
-          gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
-      return;
-    }
+    if (to_try == NULL)
+      /* no compatible elements, we cannot go on */
+      goto unknown_type;
+
     try_to_link_1 (decode_bin, pad, to_try);
-  } else {
-    GST_LOG_OBJECT (element, "multiple possibilities, delaying");
+    /* can free the list again now */
+    g_list_free (to_try);
+  }
+  return;
+
+unknown_type:
+  {
+    GST_LOG_OBJECT (pad, "unkown type found, fire signal");
+    g_signal_emit (G_OBJECT (decode_bin),
+        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
+    return;
+  }
+dont_know_yet:
+  {
+    GST_LOG_OBJECT (pad, "type is not known yet, waiting to close link");
+    return;
+  }
+many_types:
+  {
+    GST_LOG_OBJECT (pad, "many possible types, waiting to close link");
+    return;
   }
 }
 
-/* given a list of element factories, try to link one of the factories
- * to the given pad */
+/*
+ * Called when we're redirected to a new URI.
+ */
+static void
+got_redirect (GstElement * element,
+    const gchar * new_location, GstDecodeBin * decode_bin)
+{
+  g_signal_emit (decode_bin, gst_decode_bin_signals[SIGNAL_REDIRECT], 0,
+      new_location);
+}
+
+/** 
+ * given a list of element factories, try to link one of the factories
+ * to the given pad.
+ *
+ * The function returns the element that was successfully linked to the 
+ * pad.
+ */
 static GstElement *
 try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
 {
@@ -474,7 +576,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
   for (walk = factories; walk; walk = g_list_next (walk)) {
     GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
     GstElement *element;
-    gboolean ret;
+    GstPadLinkReturn ret;
 
     GST_DEBUG_OBJECT (decode_bin, "trying to link %s",
         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
@@ -492,17 +594,17 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
     GST_DEBUG_OBJECT (decode_bin, "adding %s", gst_element_get_name (element));
     gst_bin_add (GST_BIN (decode_bin), element);
 
-    /* set to ready first so it can do negotiation */
+    /* set to ready first so it is ready */
     gst_element_set_state (element, GST_STATE_READY);
 
-    /* keep out own list of elements */
+    /* keep our own list of elements */
     decode_bin->elements = g_list_prepend (decode_bin->elements, element);
 
     /* try to link the given pad to a sinkpad */
     /* FIXME, find the sinkpad by looping over the pads instead of 
      * looking it up by name */
     ret = gst_pad_link (pad, gst_element_get_pad (element, "sink"));
-    if (ret) {
+    if (ret == GST_PAD_LINK_OK) {
       const gchar *klass;
       GstElementFactory *factory;
       guint sig;
@@ -522,6 +624,12 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
            * because that would consume less memory. */
         }
       }
+      /* catch redirects */
+      if (g_signal_lookup ("got-redirect", G_OBJECT_TYPE (element))) {
+        g_signal_connect (element, "got-redirect",
+            G_CALLBACK (got_redirect), decode_bin);
+      }
+
       /* make sure we catch unlink signals */
       sig = g_signal_connect (G_OBJECT (GST_PAD_REALIZE (pad)), "unlinked",
           G_CALLBACK (unlinked), decode_bin);
@@ -532,7 +640,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
        * on it until we have a raw type */
       close_link (element, decode_bin);
       /* change the state of the element to that of the parent */
-      gst_element_sync_state_with_parent (element);
+      gst_element_set_state (element, GST_STATE_PAUSED);
       return element;
     } else {
       GST_DEBUG_OBJECT (decode_bin, "link failed on pad %s:%s",
@@ -560,6 +668,7 @@ get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
 
     GST_DEBUG_OBJECT (decode_bin, "pad parent %s",
         gst_element_get_name (parent));
+
     if (parent == GST_ELEMENT (decode_bin)) {
       GST_DEBUG_OBJECT (decode_bin, "pad is our ghostpad");
       return pad;
@@ -570,7 +679,7 @@ get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
   }
 
   GST_DEBUG_OBJECT (decode_bin, "looping over ghostpads");
-  ghostpads = gst_pad_get_ghost_pad_list (pad);
+  ghostpads = GST_REAL_PAD (pad)->ghostpads;
   while (ghostpads) {
     GstPad *ghostpad;
 
@@ -595,6 +704,10 @@ remove_element_chain (GstDecodeBin * decode_bin, GstPad * pad)
   GList *int_links;
   GstElement *elem = gst_pad_get_parent (pad);
 
+  while (GST_OBJECT_PARENT (elem) &&
+      GST_OBJECT_PARENT (elem) != GST_OBJECT (decode_bin))
+    elem = GST_ELEMENT (GST_OBJECT_PARENT (elem));
+
   GST_DEBUG_OBJECT (decode_bin, "%s:%s", GST_DEBUG_PAD_NAME (pad));
 
   /* remove all elements linked to this pad up to the ghostpad 
@@ -657,7 +770,7 @@ new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
   caps = gst_pad_get_caps (pad);
   close_pad_link (element, pad, caps, decode_bin, more);
   if (caps)
-    gst_caps_free (caps);
+    gst_caps_unref (caps);
 }
 
 /* this signal is fired when an element signals the no_more_pads signal.
@@ -673,14 +786,9 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
   GST_DEBUG_OBJECT (decode_bin, "no more pads on element %s",
       gst_element_get_name (element));
 
-  /* disconnect signals */
-  g_signal_handler_disconnect (G_OBJECT (dynamic->element), dynamic->np_sig_id);
-  g_signal_handler_disconnect (G_OBJECT (dynamic->element),
-      dynamic->nmp_sig_id);
-
   /* remove the element from the list of dynamic elements */
   decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
-  g_free (dynamic);
+  dynamic_free (dynamic);
 
   /* if we have no more dynamic elements, we have no chance of creating
    * more pads, so we fire the no_more_pads signal */
@@ -697,7 +805,6 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
 static void
 unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
 {
-  GList *walk;
   GstDynamic *dyn;
   GstElement *element;
 
@@ -709,25 +816,17 @@ unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
 
   /* if an element removes two pads, then we don't want this twice */
   element = gst_pad_get_parent (pad);
-  for (walk = decode_bin->dynamics; walk != NULL; walk = walk->next) {
-    dyn = walk->data;
-    if (dyn->element == element)
-      return;
-  }
+  if (g_list_find (decode_bin->dynamics, element) != NULL)
+    goto exit;
 
   GST_DEBUG_OBJECT (decode_bin, "pad removal while alive - chained?");
 
-  /* re-setup dynamic plugging */
-  dyn = g_new0 (GstDynamic, 1);
-  dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
-      G_CALLBACK (new_pad), dyn);
-  dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
-      G_CALLBACK (no_more_pads), dyn);
-  dyn->element = element;
-  dyn->decode_bin = decode_bin;
-
+  dyn = dynamic_create (element, decode_bin);
   /* and add this element to the dynamic elements */
   decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
+
+exit:
+  gst_object_unref (GST_OBJECT (element));
 }
 
 /* this function inspects the given element and tries to connect something
@@ -745,7 +844,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
       gst_element_get_name (element));
 
   /* loop over all the padtemplates */
-  for (pads = gst_element_get_pad_template_list (element); pads;
+  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
       pads = g_list_next (pads)) {
     GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
     const gchar *templ_name;
@@ -809,14 +908,8 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
     GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
     /* ok, this element has dynamic pads, set up the signal handlers to be
      * notified of them */
-    dyn = g_new0 (GstDynamic, 1);
-    dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
-        G_CALLBACK (new_pad), dyn);
-    dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
-        G_CALLBACK (no_more_pads), dyn);
-    dyn->element = element;
-    dyn->decode_bin = decode_bin;
 
+    dyn = dynamic_create (element, decode_bin);
     /* and add this element to the dynamic elements */
     decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
   }
@@ -844,7 +937,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
     caps = gst_pad_get_caps (pad);
     close_pad_link (element, pad, caps, decode_bin, more);
     if (caps)
-      gst_caps_free (caps);
+      gst_caps_unref (caps);
   }
 
   g_list_free (to_connect);
@@ -857,12 +950,14 @@ type_found (GstElement * typefind, guint probability, GstCaps * caps,
     GstDecodeBin * decode_bin)
 {
   gboolean dynamic;
+  GstPad *pad;
 
   GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
 
   /* autoplug the new pad with the caps that the signal gave us. */
-  close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps,
-      decode_bin, FALSE);
+  pad = gst_element_get_pad (typefind, "src");
+  close_pad_link (typefind, pad, caps, decode_bin, FALSE);
+  gst_object_unref (GST_OBJECT (pad));
 
   dynamic = gst_decode_bin_is_dynamic (decode_bin);
   if (dynamic == FALSE) {
@@ -927,23 +1022,23 @@ gst_decode_bin_change_state (GstElement * element)
 
   transition = GST_STATE_TRANSITION (element);
 
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
-  if (ret != GST_STATE_SUCCESS) {
-    return ret;
-  }
-
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
       decode_bin->numpads = 0;
-      decode_bin->threaded = FALSE;
       decode_bin->dynamics = NULL;
       break;
     case GST_STATE_READY_TO_PAUSED:
     case GST_STATE_PAUSED_TO_PLAYING:
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  switch (transition) {
     case GST_STATE_PLAYING_TO_PAUSED:
     case GST_STATE_PAUSED_TO_READY:
     case GST_STATE_READY_TO_NULL:
-      break;
     default:
       break;
   }
index dcae3bb..c87d4f9 100644 (file)
@@ -29,6 +29,7 @@
 GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
 #define GST_CAT_DEFAULT gst_play_base_bin_debug
 
+#define DEFAULT_QUEUE_THRESHOLD (2 * GST_SECOND)
 #define DEFAULT_QUEUE_SIZE  (3 * GST_SECOND)
 
 /* props */
@@ -37,9 +38,9 @@ enum
   ARG_0,
   ARG_URI,
   ARG_SUBURI,
-  ARG_THREADED,
-  ARG_NSTREAMS,
   ARG_QUEUE_SIZE,
+  ARG_QUEUE_THRESHOLD,
+  ARG_NSTREAMS,
   ARG_STREAMINFO,
   ARG_SOURCE,
   ARG_VIDEO,
@@ -56,6 +57,7 @@ enum
   GROUP_SWITCH_SIGNAL,
   LINK_STREAM_SIGNAL,
   UNLINK_STREAM_SIGNAL,
+  REDIRECT,
   LAST_SIGNAL
 };
 
@@ -70,8 +72,9 @@ static void gst_play_base_bin_get_property (GObject * object, guint prop_id,
 static GstElementStateReturn gst_play_base_bin_change_state (GstElement *
     element);
 
-static void gst_play_base_bin_add_element (GstBin * bin, GstElement * element);
-static void gst_play_base_bin_remove_element (GstBin * bin,
+static gboolean gst_play_base_bin_add_element (GstBin * bin,
+    GstElement * element);
+static gboolean gst_play_base_bin_remove_element (GstBin * bin,
     GstElement * element);
 
 extern GstElementStateReturn gst_element_set_state_func (GstElement * element,
@@ -141,13 +144,19 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
   g_object_class_install_property (gobject_klass, ARG_SUBURI,
       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
           NULL, G_PARAM_READWRITE));
-  g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
-      g_param_spec_int ("nstreams", "NStreams", "number of streams",
-          0, G_MAXINT, 0, G_PARAM_READABLE));
+
   g_object_class_install_property (gobject_klass, ARG_QUEUE_SIZE,
       g_param_spec_uint64 ("queue-size", "Queue size",
           "Size of internal queues in nanoseconds", 0, G_MAXINT64,
           DEFAULT_QUEUE_SIZE, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_klass, ARG_QUEUE_THRESHOLD,
+      g_param_spec_uint64 ("queue-threshold", "Queue threshold",
+          "Buffering threshold of internal queues in nanoseconds", 0,
+          G_MAXINT64, DEFAULT_QUEUE_THRESHOLD, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
+      g_param_spec_int ("nstreams", "NStreams", "number of streams",
+          0, G_MAXINT, 0, G_PARAM_READABLE));
   g_object_class_install_property (gobject_klass, ARG_STREAMINFO,
       g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
           G_PARAM_READABLE));
@@ -192,6 +201,12 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
       G_SIGNAL_RUN_LAST,
       G_STRUCT_OFFSET (GstPlayBaseBinClass, group_switch),
       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+  gst_play_base_bin_signals[REDIRECT] =
+      g_signal_new ("got-redirect", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstPlayBaseBinClass, got_redirect),
+      NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1,
+      G_TYPE_STRING);
 
   /* action signals */
   gst_play_base_bin_signals[LINK_STREAM_SIGNAL] =
@@ -209,7 +224,6 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_base_bin_dispose);
 
   /* we handle state changes like an element */
-  gstelement_klass->set_state = GST_ELEMENT_CLASS (element_class)->set_state;
   gstelement_klass->change_state =
       GST_DEBUG_FUNCPTR (gst_play_base_bin_change_state);
 
@@ -227,6 +241,7 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
   play_base_bin->uri = NULL;
   play_base_bin->suburi = NULL;
   play_base_bin->need_rebuild = TRUE;
+  play_base_bin->is_stream = FALSE;
   play_base_bin->source = NULL;
   play_base_bin->decoder = NULL;
   play_base_bin->subtitle = NULL;
@@ -238,8 +253,7 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
   play_base_bin->queued_groups = NULL;
 
   play_base_bin->queue_size = DEFAULT_QUEUE_SIZE;
-
-  GST_FLAG_SET (play_base_bin, GST_BIN_SELF_SCHEDULABLE);
+  play_base_bin->queue_threshold = DEFAULT_QUEUE_THRESHOLD;
 }
 
 static void
@@ -314,7 +328,7 @@ group_destroy (GstPlayBaseGroup * group)
       continue;
 
     /* remove any fakesrc elements for this preroll element */
-    for (item = gst_element_get_pad_list (group->type[n].selector);
+    for (item = GST_ELEMENT (group->type[n].selector)->pads;
         item != NULL; item = item->next) {
       GstPad *pad = GST_PAD (item->data);
       guint sig_id;
@@ -417,7 +431,7 @@ group_commit (GstPlayBaseBin * play_base_bin, gboolean fatal)
   GST_DEBUG ("signaled group done");
   g_mutex_unlock (play_base_bin->group_lock);
 
-  if (!had_active_group && GST_STATE (play_base_bin) > GST_STATE_READY) {
+  if (group && !had_active_group && GST_STATE (play_base_bin) > GST_STATE_READY) {
     setup_substreams (play_base_bin);
     GST_DEBUG ("Emitting signal");
     g_signal_emit (play_base_bin,
@@ -441,6 +455,30 @@ group_is_muted (GstPlayBaseGroup * group)
   return TRUE;
 }
 
+/*
+ * Buffer/cache checking.
+ */
+
+static gboolean
+check_queue (GstProbe * probe, GstData ** data, gpointer user_data)
+{
+  GstElement *queue = GST_ELEMENT (user_data);
+  GstPlayBaseBin *play_base_bin = g_object_get_data (G_OBJECT (queue), "pbb");
+  guint64 level = 0;
+
+  g_object_get (G_OBJECT (queue), "current-level-time", &level, NULL);
+  GST_DEBUG ("Queue size: %" GST_TIME_FORMAT, GST_TIME_ARGS (level));
+  level = level * 100 / play_base_bin->queue_threshold;
+  if (level > 100)
+    level = 100;
+
+  g_signal_emit (play_base_bin,
+      gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, level);
+
+  /* continue! */
+  return TRUE;
+}
+
 /* this signal will be fired when one of the queues with raw
  * data is filled. This means that the group building stage is over 
  * and playback of the new queued group should start */
@@ -448,7 +486,72 @@ static void
 queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
 {
   GST_DEBUG ("queue %s overrun", gst_element_get_name (element));
+
   group_commit (play_base_bin, FALSE);
+
+  g_signal_handlers_disconnect_by_func (element,
+      G_CALLBACK (queue_overrun), play_base_bin);
+}
+
+/* Used for time-based buffering. */
+static void
+queue_threshold_reached (GstElement * queue, GstPlayBaseBin * play_base_bin)
+{
+  GstProbe *probe;
+
+  GST_DEBUG ("Running");
+
+  /* play */
+  g_object_set (queue, "min-threshold-time", (guint64) 0, NULL);
+
+  if ((probe = g_object_get_data (G_OBJECT (queue), "probe"))) {
+    GstPad *sinkpad;
+
+    sinkpad = gst_element_get_pad (queue, "sink");
+    GST_DEBUG_OBJECT (play_base_bin,
+        "Removing buffer probe %p from pad %s:%s (%p)",
+        probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
+
+    g_signal_emit (play_base_bin,
+        gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
+
+    g_object_set_data (G_OBJECT (queue), "probe", NULL);
+    gst_pad_remove_probe (sinkpad, probe);
+    gst_probe_destroy (probe);
+
+    g_signal_emit (play_base_bin,
+        gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
+  }
+}
+
+static void
+queue_out_of_data (GstElement * queue, GstPlayBaseBin * play_base_bin)
+{
+  GstProbe *probe;
+
+  GST_DEBUG ("Underrun, re-caching");
+
+  /* On underrun, we want to temoprarily pause playback, set a "min-size"
+   * threshold and wait for the running signal and then play again. Take
+   * care of possible deadlocks and so on, */
+  g_object_set (queue, "min-threshold-time",
+      (guint64) play_base_bin->queue_threshold, NULL);
+
+  /* re-connect probe */
+  if (!(probe = g_object_get_data (G_OBJECT (queue), "probe"))) {
+    GstPad *sinkpad;
+
+    probe = gst_probe_new (FALSE, check_queue, queue);
+    sinkpad = gst_element_get_pad (queue, "sink");
+    gst_pad_add_probe (sinkpad, probe);
+    g_object_set_data (G_OBJECT (queue), "probe", probe);
+    GST_DEBUG_OBJECT (play_base_bin,
+        "Re-attaching buffering probe %p to pad %s:%s (%p)",
+        probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
+
+    g_signal_emit (play_base_bin,
+        gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 0);
+  }
 }
 
 /* generate a preroll element which is simply a queue. While there
@@ -491,6 +594,31 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin,
       "max-size-time", play_base_bin->queue_size, NULL);
   sig = g_signal_connect (G_OBJECT (preroll), "overrun",
       G_CALLBACK (queue_overrun), play_base_bin);
+  if (play_base_bin->is_stream &&
+      ((type == GST_STREAM_TYPE_VIDEO &&
+              group->type[GST_STREAM_TYPE_AUDIO - 1].npads == 0) ||
+          (type == GST_STREAM_TYPE_AUDIO &&
+              group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0))) {
+    GstProbe *probe;
+    GstPad *sinkpad;
+
+    g_signal_connect (G_OBJECT (preroll), "running",
+        G_CALLBACK (queue_threshold_reached), play_base_bin);
+    g_object_set (G_OBJECT (preroll),
+        "min-threshold-time", (guint64) play_base_bin->queue_threshold, NULL);
+
+    /* give updates on queue size */
+    probe = gst_probe_new (FALSE, check_queue, preroll);
+    sinkpad = gst_element_get_pad (preroll, "sink");
+    gst_pad_add_probe (sinkpad, probe);
+    GST_DEBUG_OBJECT (play_base_bin, "Attaching probe %p to pad %s:%s (%p)",
+        probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
+    g_object_set_data (G_OBJECT (preroll), "pbb", play_base_bin);
+    g_object_set_data (G_OBJECT (preroll), "probe", probe);
+
+    g_signal_connect (G_OBJECT (preroll), "underrun",
+        G_CALLBACK (queue_out_of_data), play_base_bin);
+  }
   /* keep a ref to the signal id so that we can disconnect the signal callback
    * when we are done with the preroll */
   g_object_set_data (G_OBJECT (preroll), "signal_id", GINT_TO_POINTER (sig));
@@ -583,7 +711,7 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
   GstPlayBaseGroup *group = get_building_group (play_base_bin);
 
   capsstr = gst_caps_to_string (caps);
-  g_message /*warning */ ("don't know how to handle %s", capsstr);
+  g_message ("don't know how to handle %s", capsstr);
 
   /* add the stream to the list */
   info = gst_stream_info_new (GST_OBJECT (pad), GST_STREAM_TYPE_UNKNOWN,
@@ -807,7 +935,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
     g_warning ("no type on pad %s:%s",
         GST_DEBUG_PAD_NAME (GST_PAD_REALIZE (pad)));
     if (caps)
-      gst_caps_free (caps);
+      gst_caps_unref (caps);
     return;
   }
 
@@ -848,7 +976,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
   gst_pad_link (pad, sinkpad);
 
   /* add the stream to the list */
-  gst_caps_free (caps);
+  gst_caps_unref (caps);
   info->origin = GST_OBJECT (pad);
 
   /* select 1st for now - we'll select a preferred one after preroll */
@@ -906,67 +1034,6 @@ state_change (GstElement * element,
 }
 
 /*
- * Buffer/cache checking. FIXME: make configurable.
- * Note that we could also do this (buffering) at the
- * preroll-level. The advantage there is that it'd
- * allow us to cache in time-units rather than byte-
- * units. Ohwell...
- */
-
-static gboolean
-check_queue (GstProbe * probe, GstData ** data, gpointer user_data)
-{
-  GstElement *queue = GST_ELEMENT (user_data);
-  GstPlayBaseBin *play_base_bin = g_object_get_data (G_OBJECT (queue), "pbb");
-  guint level = 0;
-
-  g_object_get (G_OBJECT (queue), "current-level-bytes", &level, NULL);
-  GST_DEBUG ("Queue size: %u bytes", level);
-  g_signal_emit (play_base_bin,
-      gst_play_base_bin_signals[BUFFERING_SIGNAL], 0,
-      level * 100 / (512 * 1024));
-
-  /* continue! */
-  return TRUE;
-}
-
-static void
-buffer_underrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GST_DEBUG ("Underrun, re-caching");
-
-  /* On underrun, we want to temoprarily pause playback, set a "min-size"
-   * treshold and wait for the running signal and then play again. Take
-   * care of possible deadlocks and so on, */
-  g_object_set (queue, "min-threshold-bytes", 64 * 1024, NULL);
-
-  g_signal_emit (play_base_bin,
-      gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 0);
-}
-
-static void
-buffer_running (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GST_DEBUG ("Running");
-
-  /* When we had an underrun, we now want to play again. */
-  g_object_set (queue, "min-threshold-bytes", 0,
-      "max-size-bytes", 512 * 1024, NULL);
-}
-
-static void
-buffer_overrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GST_DEBUG ("Overrun, leaking upstream and flushing next few buffers");
-
-  /* we want to decrease max-size here so the next few bytes are flushed */
-  g_object_set (queue, "max-size-bytes", 448 * 1024, NULL);
-
-  g_signal_emit (play_base_bin,
-      gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
-}
-
-/*
  * Generate source ! subparse bins.
  */
 
@@ -980,9 +1047,12 @@ setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
   if (!source)
     return NULL;
 
-  subparse = gst_element_factory_make ("subparse", NULL);
+  if (!(subparse = gst_element_factory_make ("subparse", NULL))) {
+    gst_object_unref (GST_OBJECT (source));
+    return NULL;
+  }
   name = g_strdup_printf ("subbin");
-  subbin = gst_thread_new (name);
+  subbin = gst_bin_new (name);
   g_free (name);
 
   gst_bin_add_many (GST_BIN (subbin), source, subparse, NULL);
@@ -999,12 +1069,9 @@ setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
  */
 
 static GstElement *
-gen_source_element (GstPlayBaseBin * play_base_bin,
-    GstElement ** subbin, gboolean * _is_stream)
+gen_source_element (GstPlayBaseBin * play_base_bin, GstElement ** subbin)
 {
-  GstElement *source, *queue, *bin;
-  GstProbe *probe;
-  gboolean is_stream;
+  GstElement *source;
 
   /* stip subtitle from uri */
   if (!play_base_bin->uri)
@@ -1023,34 +1090,12 @@ gen_source_element (GstPlayBaseBin * play_base_bin,
     return NULL;
 
   /* lame - FIXME, maybe we can use seek_types/mask here? */
-  *_is_stream = is_stream = !strncmp (play_base_bin->uri, "http://", 7) ||
-      !strncmp (play_base_bin->uri, "mms://", 6);
-  if (!is_stream)
-    return source;
-
-  /* buffer */
-  bin = gst_thread_new ("sourcebin");
-  queue = gst_element_factory_make ("queue", "buffer");
-  g_object_set (queue, "max-size-bytes", 512 * 1024,
-      "max-size-buffers", 0, NULL);
-  /* I'd like it to be leaky too, but only for live sources. How? */
-  g_signal_connect (queue, "underrun", G_CALLBACK (buffer_underrun),
-      play_base_bin);
-  g_signal_connect (queue, "running", G_CALLBACK (buffer_running),
-      play_base_bin);
-  g_signal_connect (queue, "overrun", G_CALLBACK (buffer_overrun),
-      play_base_bin);
-
-  /* give updates on queue size */
-  probe = gst_probe_new (FALSE, check_queue, queue);
-  gst_pad_add_probe (gst_element_get_pad (source, "src"), probe);
-  g_object_set_data (G_OBJECT (queue), "pbb", play_base_bin);
-
-  gst_element_link (source, queue);
-  gst_bin_add_many (GST_BIN (bin), source, queue, NULL);
-  gst_element_add_ghost_pad (bin, gst_element_get_pad (queue, "src"), "src");
-
-  return bin;
+  play_base_bin->is_stream = !strncmp (play_base_bin->uri, "http://", 7) ||
+      !strncmp (play_base_bin->uri, "mms://", 6) ||
+      !strncmp (play_base_bin->uri, "rtp://", 6) ||
+      !strncmp (play_base_bin->uri, "rtsp://", 7);
+
+  return source;
 }
 
 /* Setup the substreams (to be called right after group_commit ()) */
@@ -1097,18 +1142,29 @@ setup_substreams (GstPlayBaseBin * play_base_bin)
   }
 }
 
+/*
+ * Called when we're redirected to a new URI.
+ */
+static void
+got_redirect (GstElement * element, const gchar * new_location, gpointer data)
+{
+  gchar **location = data;
+
+  if (!*location)
+    *location = g_strdup (new_location);
+}
+
 /* construct and run the source and decoder elements until we found
  * all the streams or until a preroll queue has been filled.
- */
+*/
 static gboolean
 setup_source (GstPlayBaseBin * play_base_bin,
-    gboolean * _stream, GError ** error)
+    gchar ** new_location, GError ** error)
 {
   GstElement *old_src;
   GstElement *old_dec;
   GstPad *srcpad = NULL;
   GstElement *subbin;
-  gboolean stream;
 
   if (!play_base_bin->need_rebuild)
     return TRUE;
@@ -1119,8 +1175,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
   old_src = play_base_bin->source;
 
   /* create and configure an element that can handle the uri */
-  play_base_bin->source = gen_source_element (play_base_bin, &subbin, &stream);
-  *_stream = stream;
+  play_base_bin->source = gen_source_element (play_base_bin, &subbin);
 
   if (!play_base_bin->source) {
     /* whoops, could not create the source element */
@@ -1137,11 +1192,14 @@ setup_source (GstPlayBaseBin * play_base_bin,
     }
     gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source);
     g_object_notify (G_OBJECT (play_base_bin), "source");
+
     /* make sure the new element has the same state as the parent */
+#if 0
     if (gst_bin_sync_children_state (GST_BIN (play_base_bin->thread)) ==
         GST_STATE_FAILURE) {
       return FALSE;
     }
+#endif
   }
 
   /* remove the old decoder now, if any */
@@ -1180,7 +1238,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
     /* assume we are going to have no output streams */
     gboolean no_out = TRUE;
 
-    for (pads = gst_element_get_pad_list (play_base_bin->source);
+    for (pads = GST_ELEMENT (play_base_bin->source)->pads;
         pads; pads = g_list_next (pads)) {
       GstPad *pad = GST_PAD (pads->data);
       GstStructure *structure;
@@ -1198,7 +1256,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
       if (caps == NULL || gst_caps_is_empty (caps) ||
           gst_caps_get_size (caps) == 0) {
         if (caps != NULL)
-          gst_caps_free (caps);
+          gst_caps_unref (caps);
         continue;
       }
 
@@ -1212,7 +1270,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
         is_raw = TRUE;
       }
 
-      gst_caps_free (caps);
+      gst_caps_unref (caps);
     }
     if (is_raw) {
       no_more_pads (play_base_bin->source, play_base_bin);
@@ -1246,6 +1304,8 @@ setup_source (GstPlayBaseBin * play_base_bin,
         gst_object_unref (GST_OBJECT (old_dec));
     }
 
+    g_signal_connect (play_base_bin->decoder, "got_redirect",
+        G_CALLBACK (got_redirect), new_location);
     res = gst_pad_link (srcpad,
         gst_element_get_pad (play_base_bin->decoder, "sink"));
     if (!res) {
@@ -1259,7 +1319,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
     sig3 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "no-more-pads",
         G_CALLBACK (no_more_pads), play_base_bin);
 
-    if (!stream) {
+    if (!play_base_bin->is_stream) {
       sig4 = g_signal_connect (G_OBJECT (play_base_bin->decoder),
           "unknown-type", G_CALLBACK (unknown_type), play_base_bin);
       sig5 = g_signal_connect (G_OBJECT (play_base_bin->thread), "error",
@@ -1270,7 +1330,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
        * the signal handlers then
        */
       g_mutex_lock (play_base_bin->group_lock);
-      if (gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING) ==
+      if (gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED) ==
           GST_STATE_SUCCESS) {
         GST_DEBUG ("waiting for first group...");
         sig6 = g_signal_connect (G_OBJECT (play_base_bin->thread),
@@ -1300,7 +1360,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
       /* make subs iterate from now on */
       gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->subtitle);
     }
-    if (!stream) {
+    if (!play_base_bin->is_stream) {
       setup_substreams (play_base_bin);
     }
   }
@@ -1550,7 +1610,7 @@ play_base_eos (GstBin * bin, GstPlayBaseBin * play_base_bin)
 
   GST_LOG ("forwarding EOS");
 
-  gst_element_set_eos (GST_ELEMENT (play_base_bin));
+  //gst_element_set_eos (GST_ELEMENT (play_base_bin));
 }
 
 static GstElementStateReturn
@@ -1564,32 +1624,20 @@ gst_play_base_bin_change_state (GstElement * element)
   switch (GST_STATE_TRANSITION (element)) {
     case GST_STATE_NULL_TO_READY:
     {
-      GstScheduler *sched;
-
-      play_base_bin->thread = gst_thread_new ("internal_thread");
-      sched = gst_scheduler_factory_make ("opt", play_base_bin->thread);
-      if (sched) {
-        gst_element_set_scheduler (play_base_bin->thread, sched);
+      play_base_bin->thread = gst_bin_new ("internal_thread");
 
-        gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
+      gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
 
-        g_signal_connect (play_base_bin->thread, "found_tag",
-            G_CALLBACK (gst_play_base_bin_found_tag), play_base_bin);
-      } else {
-        g_warning ("could not get 'opt' scheduler");
-        gst_object_unref (GST_OBJECT (play_base_bin->thread));
-        play_base_bin->thread = NULL;
-
-        ret = GST_STATE_FAILURE;
-      }
+      g_signal_connect (play_base_bin->thread, "found_tag",
+          G_CALLBACK (gst_play_base_bin_found_tag), play_base_bin);
       break;
     }
     case GST_STATE_READY_TO_PAUSED:
     {
       GError *error = NULL;
-      gboolean stream;
+      gchar *new_location = NULL;
 
-      if (!setup_source (play_base_bin, &stream, &error) || error != NULL) {
+      if (!setup_source (play_base_bin, &new_location, &error) || error != NULL) {
         if (!error) {
           /* opening failed but no error - hellup */
           GST_ELEMENT_ERROR (GST_ELEMENT (play_base_bin), STREAM,
@@ -1602,7 +1650,12 @@ gst_play_base_bin_change_state (GstElement * element)
           g_error_free (error);
         }
         ret = GST_STATE_FAILURE;
-      } else if (stream) {
+      } else if (new_location) {
+        g_signal_emit (play_base_bin, gst_play_base_bin_signals[REDIRECT],
+            0, new_location);
+        g_free (new_location);
+        ret = GST_STATE_FAILURE;
+      } else if (play_base_bin->is_stream) {
         ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
       } else {
         const GList *item;
@@ -1652,6 +1705,7 @@ gst_play_base_bin_change_state (GstElement * element)
                 ("File \"%s\" is not a media file", play_base_bin->uri),
                 (NULL));
           }
+          gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
           ret = GST_STATE_FAILURE;
         } else {
           ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
@@ -1666,7 +1720,7 @@ gst_play_base_bin_change_state (GstElement * element)
             G_CALLBACK (gst_play_base_bin_error), play_base_bin);
         g_signal_connect (G_OBJECT (play_base_bin->thread), "eos",
             G_CALLBACK (play_base_eos), play_base_bin);
-        if (!stream) {
+        if (!play_base_bin->is_stream) {
           GST_DEBUG ("emit signal");
           g_signal_emit (play_base_bin,
               gst_play_base_bin_signals[SETUP_OUTPUT_PADS_SIGNAL], 0);
@@ -1713,7 +1767,7 @@ gst_play_base_bin_change_state (GstElement * element)
 /* virtual function to add elements to this bin. The idea is to
  * wrap the element in a thread automatically.
  */
-static void
+static gboolean
 gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
 {
   GstPlayBaseBin *play_base_bin;
@@ -1721,15 +1775,12 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
   play_base_bin = GST_PLAY_BASE_BIN (bin);
 
   if (play_base_bin->thread) {
-    GstScheduler *sched;
-    GstClock *clock;
-
     if (play_base_bin->threaded) {
       gchar *name;
       GstElement *thread;
 
       name = g_strdup_printf ("thread_%s", gst_element_get_name (element));
-      thread = gst_thread_new (name);
+      thread = gst_bin_new (name);
       g_free (name);
 
       gst_bin_add (GST_BIN (thread), element);
@@ -1739,21 +1790,19 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
     if (GST_STATE (play_base_bin) > GST_STATE_READY) {
       gst_element_set_state (element, GST_STATE (play_base_bin));
     }
-
-    /* hack, the clock is not correctly distributed in the core */
-    sched = gst_element_get_scheduler (GST_ELEMENT (play_base_bin->thread));
-    clock = gst_scheduler_get_clock (sched);
-    gst_scheduler_set_clock (sched, clock);
   } else {
     g_warning ("adding elements is not allowed in NULL");
+    return FALSE;
   }
+
+  return TRUE;
 }
 
 /* virtual function to remove an element from this bin. We have to make
  * sure that we also remove the thread that we used as a container for
  * this element.
  */
-static void
+static gboolean
 gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
 {
   GstPlayBaseBin *play_base_bin;
@@ -1786,7 +1835,9 @@ gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
     }
   } else {
     g_warning ("removing elements is not allowed in NULL");
+    return FALSE;
   }
+  return TRUE;
 }
 
 static void
index e30db72..538aa66 100644 (file)
@@ -68,12 +68,14 @@ struct _GstPlayBaseBin {
   /* properties */
   gboolean      threaded;
   guint64       queue_size;
+  guint                 queue_threshold;
 
   gint          current[NUM_TYPES];
 
   /* internal thread */
   GstElement   *thread;
   gchar        *uri, *suburi;
+  gboolean      is_stream;
   GstElement   *source;
   GstElement   *decoder;
   GstElement   *subtitle; /* additional filesrc ! subparse bin */
@@ -103,6 +105,10 @@ struct _GstPlayBaseBinClass {
                                 gint            percentage);
   void (*group_switch)         (GstPlayBaseBin *play_base_bin);
 
+  /* Called on redirect */
+  void (*got_redirect)         (GstPlayBaseBin *play_base_bin,
+                                const gchar    *new_location);
+
   /* action signals */
   gboolean (*link_stream)      (GstPlayBaseBin *play_base_bin, 
                                 GstStreamInfo *info,
index 769abf6..abed380 100644 (file)
@@ -49,6 +49,7 @@ struct _GstPlayBin
   GstElement *video_sink;
   GstElement *visualisation;
   GstElement *volume_element;
+  GstElement *textoverlay_element;
   gfloat volume;
 
   /* these are the currently active sinks */
@@ -65,6 +66,9 @@ struct _GstPlayBin
 
   /* boolean to see if we're currently switching groups */
   gboolean group_switch;
+
+  /* font description */
+  gchar *font_desc;
 };
 
 struct _GstPlayBinClass
@@ -80,7 +84,8 @@ enum
   ARG_VIDEO_SINK,
   ARG_VIS_PLUGIN,
   ARG_VOLUME,
-  ARG_FRAME
+  ARG_FRAME,
+  ARG_FONT_DESC
 };
 
 /* signals */
@@ -182,13 +187,18 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
       g_param_spec_object ("vis-plugin", "Vis plugin",
           "the visualization element to use (NULL = none)",
           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (gobject_klass), ARG_VOLUME,
+  g_object_class_install_property (gobject_klass, ARG_VOLUME,
       g_param_spec_double ("volume", "volume", "volume",
           0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (gobject_klass), ARG_FRAME,
+  g_object_class_install_property (gobject_klass, ARG_FRAME,
       g_param_spec_boxed ("frame", "Frame",
           "The last frame (NULL = no video available)",
           GST_TYPE_BUFFER, G_PARAM_READABLE));
+  g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
+      g_param_spec_string ("subtitle-font-desc",
+          "Subtitle font description",
+          "Pango font description of font "
+          "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
 
   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose);
 
@@ -216,16 +226,15 @@ gst_play_bin_init (GstPlayBin * play_bin)
   play_bin->audio_sink = NULL;
   play_bin->visualisation = NULL;
   play_bin->volume_element = NULL;
+  play_bin->textoverlay_element = NULL;
   play_bin->volume = 1.0;
   play_bin->seekables = NULL;
   play_bin->sinks = NULL;
   play_bin->frame = NULL;
+  play_bin->font_desc = NULL;
   play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
       NULL, (GDestroyNotify) gst_object_unref);
   play_bin->group_switch = FALSE;
-
-  /* no iterate is needed */
-  GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE);
 }
 
 static void
@@ -253,7 +262,8 @@ gst_play_bin_dispose (GObject * object)
     gst_object_unref (GST_OBJECT (play_bin->visualisation));
     play_bin->visualisation = NULL;
   }
-
+  g_free (play_bin->font_desc);
+  play_bin->font_desc = NULL;
 
   if (G_OBJECT_CLASS (parent_class)->dispose) {
     G_OBJECT_CLASS (parent_class)->dispose (object);
@@ -314,6 +324,14 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
             play_bin->volume, NULL);
       }
       break;
+    case ARG_FONT_DESC:
+      g_free (play_bin->font_desc);
+      play_bin->font_desc = g_strdup (g_value_get_string (value));
+      if (play_bin->textoverlay_element) {
+        g_object_set (G_OBJECT (play_bin->textoverlay_element),
+            "font-desc", g_value_get_string (value), NULL);
+      }
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -406,7 +424,7 @@ gen_video_element (GstPlayBin * play_bin)
   if (play_bin->video_sink) {
     sink = play_bin->video_sink;
   } else {
-    sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
+    sink = gst_element_factory_make ("autovideosink", "sink");
   }
   gst_object_ref (GST_OBJECT (sink));
   g_hash_table_insert (play_bin->cache, "video_sink", sink);
@@ -455,6 +473,11 @@ gen_text_element (GstPlayBin * play_bin)
   overlay = gst_element_factory_make ("textoverlay", "overlay");
   g_object_set (G_OBJECT (overlay),
       "halign", "center", "valign", "bottom", NULL);
+  play_bin->textoverlay_element = overlay;
+  if (play_bin->font_desc) {
+    g_object_set (G_OBJECT (play_bin->textoverlay_element),
+        "font-desc", play_bin->font_desc, NULL);
+  }
   vbin = gen_video_element (play_bin);
   if (!overlay) {
     g_warning ("No overlay (pango) element, subtitles disabled");
@@ -511,7 +534,7 @@ gen_audio_element (GstPlayBin * play_bin)
   if (play_bin->audio_sink) {
     sink = play_bin->audio_sink;
   } else {
-    sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
+    sink = gst_element_factory_make ("autoaudiosink", "sink");
     play_bin->audio_sink = GST_ELEMENT (gst_object_ref (GST_OBJECT (sink)));
   }
 
@@ -674,6 +697,9 @@ remove_sinks (GstPlayBin * play_bin)
     gst_buffer_unref (play_bin->frame);
     play_bin->frame = NULL;
   }
+
+  play_bin->textoverlay_element = NULL;
+  play_bin->volume_element = NULL;
 }
 
 /* loop over the streams and set up the pipeline to play this
@@ -855,7 +881,7 @@ gst_play_bin_send_event (GstElement * element, GstEvent * event)
 
   play_bin = GST_PLAY_BIN (element);
 
-  state = gst_element_get_state (element);
+  gst_element_get_state (element, &state, NULL, NULL);
   /* we pause the pipeline first before sending the event. We only
    * do this if the pipeline was playing. */
   if (state == GST_STATE_PLAYING) {
index 160738c..44ab638 100644 (file)
@@ -206,7 +206,7 @@ gst_stream_info_dispose (GObject * object)
   g_free (stream_info->decoder);
   stream_info->decoder = NULL;
   if (stream_info->caps) {
-    gst_caps_free (stream_info->caps);
+    gst_caps_unref (stream_info->caps);
     stream_info->caps = NULL;
   }
 
@@ -225,7 +225,7 @@ stream_info_change_state (GstElement * element,
     /* state change will annoy us */
     g_return_if_fail (stream_info->mute == TRUE);
     GST_DEBUG_OBJECT (stream_info, "Re-muting pads after state-change");
-    gst_pad_set_active_recursive (GST_PAD (stream_info->object), FALSE);
+    //gst_pad_set_active_recursive (GST_PAD (stream_info->object), FALSE);
   }
 }
 
@@ -241,8 +241,8 @@ gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
 
   if (mute != stream_info->mute) {
     stream_info->mute = mute;
-    gst_pad_set_active_recursive ((GstPad *)
-        GST_PAD_REALIZE (stream_info->object), !mute);
+    //gst_pad_set_active_recursive ((GstPad *)
+    //    GST_PAD_REALIZE (stream_info->object), !mute);
 
     if (mute) {
       g_signal_connect (gst_pad_get_parent ((GstPad *)
index d4f9a26..153188a 100644 (file)
@@ -58,12 +58,13 @@ static void gst_stream_selector_base_init (GstStreamSelectorClass * klass);
 static void gst_stream_selector_class_init (GstStreamSelectorClass * klass);
 
 static GstCaps *gst_stream_selector_get_caps (GstPad * pad);
-static GstPadLinkReturn gst_stream_selector_link (GstPad * pad,
-    const GstCaps * caps);
+static gboolean gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps);
 static GList *gst_stream_selector_get_linked_pads (GstPad * pad);
 static GstPad *gst_stream_selector_request_new_pad (GstElement * element,
     GstPadTemplate * templ, const gchar * unused);
-static void gst_stream_selector_chain (GstPad * pad, GstData * data);
+static gboolean gst_stream_selector_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_stream_selector_chain (GstPad * pad,
+    GstBuffer * buffer);
 
 static GstElementClass *parent_class = NULL;
 
@@ -134,8 +135,8 @@ gst_stream_selector_init (GstStreamSelector * sel)
   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_pad_set_internal_link_function (sel->srcpad,
       GST_DEBUG_FUNCPTR (gst_stream_selector_get_linked_pads));
-  gst_pad_set_link_function (sel->srcpad,
-      GST_DEBUG_FUNCPTR (gst_stream_selector_link));
+  gst_pad_set_setcaps_function (sel->srcpad,
+      GST_DEBUG_FUNCPTR (gst_stream_selector_setcaps));
   gst_pad_set_getcaps_function (sel->srcpad,
       GST_DEBUG_FUNCPTR (gst_stream_selector_get_caps));
   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
@@ -173,7 +174,6 @@ gst_stream_selector_get_linked_pad (GstPad * pad)
 static GstCaps *
 gst_stream_selector_get_caps (GstPad * pad)
 {
-  GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
   GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
 
   if (!otherpad) {
@@ -181,19 +181,17 @@ gst_stream_selector_get_caps (GstPad * pad)
         "Pad %s not linked, returning ANY", gst_pad_get_name (pad));
 
     return gst_caps_new_any ();
-  } else if (otherpad == sel->last_active_sinkpad && sel->in_chain) {
-    return gst_caps_copy (GST_PAD_CAPS (sel->last_active_sinkpad));
   }
 
   GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
-      "Pad %s is linked (to %s), returning allowed-caps",
+      "Pad %s is linked (to %s), returning peer-caps",
       gst_pad_get_name (pad), gst_pad_get_name (otherpad));
 
-  return gst_pad_get_allowed_caps (otherpad);
+  return gst_pad_peer_get_caps (otherpad);
 }
 
-static GstPadLinkReturn
-gst_stream_selector_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
 
@@ -202,14 +200,16 @@ gst_stream_selector_link (GstPad * pad, const GstCaps * caps)
         "Pad %s not linked, returning %s",
         gst_pad_get_name (pad), GST_PAD_IS_SINK (pad) ? "ok" : "delayed");
 
-    return GST_PAD_IS_SINK (pad) ? GST_PAD_LINK_OK : GST_PAD_LINK_DELAYED;
+    return FALSE;
   }
 
   GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
       "Pad %s is linked (to %s), returning other-trysetcaps",
       gst_pad_get_name (pad), gst_pad_get_name (otherpad));
 
-  return gst_pad_try_set_caps (otherpad, caps);
+  gst_pad_set_caps (otherpad, caps);
+
+  return TRUE;
 }
 
 static GList *
@@ -241,12 +241,12 @@ gst_stream_selector_request_new_pad (GstElement * element,
     sel->last_active_sinkpad = sinkpad;
   g_free (name);
 
-  gst_pad_set_link_function (sinkpad,
-      GST_DEBUG_FUNCPTR (gst_stream_selector_link));
   gst_pad_set_getcaps_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_stream_selector_get_caps));
   gst_pad_set_chain_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_stream_selector_chain));
+  gst_pad_set_event_function (sinkpad,
+      GST_DEBUG_FUNCPTR (gst_stream_selector_event));
   gst_pad_set_internal_link_function (sinkpad,
       GST_DEBUG_FUNCPTR (gst_stream_selector_get_linked_pads));
   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
@@ -254,33 +254,36 @@ gst_stream_selector_request_new_pad (GstElement * element,
   return sinkpad;
 }
 
-static void
-gst_stream_selector_chain (GstPad * pad, GstData * data)
+static gboolean
+gst_stream_selector_event (GstPad * pad, GstEvent * event)
 {
-  GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
+  GstStreamSelector *sel = GST_STREAM_SELECTOR (GST_PAD_PARENT (pad));
+
+  /* forward */
+  GST_DEBUG_OBJECT (sel, "Forwarding event %p from pad %s",
+      event, GST_OBJECT_NAME (pad));
+
+  return gst_pad_push_event (sel->srcpad, event);
+}
+
+static GstFlowReturn
+gst_stream_selector_chain (GstPad * pad, GstBuffer * buffer)
+{
+  GstStreamSelector *sel = GST_STREAM_SELECTOR (GST_PAD_PARENT (pad));
 
   /* first, check if the active pad changed. If so, redo
    * negotiation and fail if that fails. */
   if (pad != sel->last_active_sinkpad) {
-    GstPadLinkReturn ret;
-
     GST_LOG_OBJECT (sel, "stream change detected, switching from %s to %s",
         sel->last_active_sinkpad ?
         gst_pad_get_name (sel->last_active_sinkpad) : "none",
         gst_pad_get_name (pad));
     sel->last_active_sinkpad = pad;
-    sel->in_chain = TRUE;
-    ret = gst_pad_renegotiate (sel->srcpad);
-    sel->in_chain = FALSE;
-    if (GST_PAD_LINK_FAILED (ret)) {
-      GST_ELEMENT_ERROR (sel, CORE, NEGOTIATION, (NULL), (NULL));
-      sel->last_active_sinkpad = NULL;
-      return;
-    }
   }
 
   /* forward */
-  GST_DEBUG_OBJECT (sel, "Forwarding %s %p from pad %s",
-      GST_IS_EVENT (data) ? "event" : "buffer", data, gst_pad_get_name (pad));
-  gst_pad_push (sel->srcpad, data);
+  GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s",
+      buffer, GST_OBJECT_NAME (pad));
+
+  return gst_pad_push (sel->srcpad, buffer);
 }
index 61dbaa4..6b36781 100644 (file)
@@ -28,7 +28,7 @@ gen_video_element ()
   GstElement *conv;
   GstElement *sink;
 
-  element = gst_thread_new ("vbin");
+  element = gst_bin_new ("vbin");
   conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
   sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
 
@@ -49,7 +49,7 @@ gen_audio_element ()
   GstElement *conv;
   GstElement *sink;
 
-  element = gst_thread_new ("abin");
+  element = gst_bin_new ("abin");
   conv = gst_element_factory_make ("audioconvert", "conv");
   sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
 
@@ -130,8 +130,7 @@ main (gint argc, gchar * argv[])
     g_print ("could not play\n");
     return -1;
   }
-
-  gst_main ();
+  //gst_main ();
 
   return 0;
 }
index cc942e9..5bc6637 100644 (file)
@@ -1183,8 +1183,6 @@ gst_xvimagesink_getcaps (GstBaseSink * bsink)
 
   xvimagesink = GST_XVIMAGESINK (bsink);
 
-  g_print ("getcaps\n");
-
   if (xvimagesink->xcontext)
     return gst_caps_ref (xvimagesink->xcontext->caps);