Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / ext / ogg / gstoggdemux.c
index 2426b72..ad5ab26 100644 (file)
@@ -131,10 +131,10 @@ static gboolean gst_ogg_demux_receive_event (GstElement * element,
 static void gst_ogg_pad_dispose (GObject * object);
 static void gst_ogg_pad_finalize (GObject * object);
 
-static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad);
-static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQuery * query);
-static gboolean gst_ogg_pad_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_ogg_pad_getcaps (GstPad * pad);
+static gboolean gst_ogg_pad_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+static gboolean gst_ogg_pad_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
 static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain,
     guint32 serialno);
 
@@ -169,12 +169,9 @@ gst_ogg_pad_init (GstOggPad * pad)
 {
   gst_pad_set_event_function (GST_PAD (pad),
       GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
-  gst_pad_set_getcaps_function (GST_PAD (pad),
-      GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps));
-  gst_pad_set_query_type_function (GST_PAD (pad),
-      GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types));
   gst_pad_set_query_function (GST_PAD (pad),
       GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
+  gst_pad_use_fixed_caps (GST_PAD (pad));
 
   pad->mode = GST_OGG_PAD_MODE_INIT;
 
@@ -183,7 +180,7 @@ gst_ogg_pad_init (GstOggPad * pad)
 
   pad->start_time = GST_CLOCK_TIME_NONE;
 
-  pad->last_stop = GST_CLOCK_TIME_NONE;
+  pad->position = GST_CLOCK_TIME_NONE;
 
   pad->have_type = FALSE;
   pad->continued = NULL;
@@ -243,31 +240,13 @@ gst_ogg_pad_finalize (GObject * object)
   G_OBJECT_CLASS (gst_ogg_pad_parent_class)->finalize (object);
 }
 
-static const GstQueryType *
-gst_ogg_pad_query_types (GstPad * pad)
-{
-  static const GstQueryType query_types[] = {
-    GST_QUERY_DURATION,
-    GST_QUERY_SEEKING,
-    0
-  };
-
-  return query_types;
-}
-
-static GstCaps *
-gst_ogg_pad_getcaps (GstPad * pad)
-{
-  return gst_caps_ref (GST_PAD_CAPS (pad));
-}
-
 static gboolean
-gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
+gst_ogg_pad_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
   gboolean res = TRUE;
   GstOggDemux *ogg;
 
-  ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
+  ogg = GST_OGG_DEMUX (parent);
 
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_DURATION:
@@ -359,11 +338,10 @@ gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
     }
 
     default:
-      res = gst_pad_query_default (pad, query);
+      res = gst_pad_query_default (pad, parent, query);
       break;
   }
 done:
-  gst_object_unref (ogg);
 
   return res;
 
@@ -407,12 +385,12 @@ error:
 }
 
 static gboolean
-gst_ogg_pad_event (GstPad * pad, GstEvent * event)
+gst_ogg_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
   gboolean res;
   GstOggDemux *ogg;
 
-  ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
+  ogg = GST_OGG_DEMUX (parent);
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
@@ -421,10 +399,9 @@ gst_ogg_pad_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
       break;
     default:
-      res = gst_pad_event_default (pad, event);
+      res = gst_pad_event_default (pad, parent, event);
       break;
   }
-  gst_object_unref (ogg);
 
   return res;
 }
@@ -442,7 +419,7 @@ gst_ogg_pad_reset (GstOggPad * pad)
   pad->continued = NULL;
 
   pad->last_ret = GST_FLOW_OK;
-  pad->last_stop = GST_CLOCK_TIME_NONE;
+  pad->position = GST_CLOCK_TIME_NONE;
   pad->current_granule = -1;
   pad->keyframe_granule = -1;
   pad->is_eos = FALSE;
@@ -625,14 +602,14 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
     goto not_added;
 
   buf = gst_buffer_new_and_alloc (packet->bytes - offset - trim);
-  gst_buffer_set_caps (buf, GST_PAD_CAPS (pad));
 
   /* set delta flag for OGM content */
   if (delta_unit)
     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
 
   /* copy packet in buffer */
-  memcpy (buf->data, packet->packet + offset, packet->bytes - offset - trim);
+  gst_buffer_fill (buf, 0, packet->packet + offset,
+      packet->bytes - offset - trim);
 
   GST_BUFFER_TIMESTAMP (buf) = out_timestamp;
   GST_BUFFER_DURATION (buf) = out_duration;
@@ -645,7 +622,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
     pad->discont = FALSE;
   }
 
-  pad->last_stop = ogg->segment.last_stop;
+  pad->position = ogg->segment.position;
 
   /* don't push the header packets when we are asked to skip them */
   if (!packet->b_o_s || push_headers) {
@@ -662,7 +639,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
 
   /* check if valid granulepos, then we can calculate the current
    * position. We know the granule for each packet but we only want to update
-   * the last_stop when we have a valid granulepos on the packet because else
+   * the position when we have a valid granulepos on the packet because else
    * our time jumps around for the different streams. */
   if (packet->granulepos < 0)
     goto done;
@@ -682,7 +659,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
   }
 
   /* and store as the current position */
-  gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME, current_time);
+  ogg->segment.position = current_time;
 
   GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT,
       GST_TIME_ARGS (current_time));
@@ -797,7 +774,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
   if (!pad->have_type) {
     pad->have_type = gst_ogg_stream_setup_map (&pad->map, packet);
     if (!pad->have_type) {
-      pad->map.caps = gst_caps_new_simple ("application/x-unknown", NULL);
+      pad->map.caps = gst_caps_new_empty_simple ("application/x-unknown");
     }
     if (pad->map.is_skeleton) {
       GST_DEBUG_OBJECT (ogg, "we have a fishead");
@@ -957,6 +934,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
 
         if (start_time != G_MAXUINT64) {
           gint64 segment_time;
+          GstSegment segment;
 
           GST_DEBUG_OBJECT (ogg, "start_time:  %" GST_TIME_FORMAT,
               GST_TIME_ARGS (start_time));
@@ -968,6 +946,8 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
             segment_time = chain->begin_time;
 
           /* create the newsegment event we are going to send out */
+          gst_segment_init (&segment, GST_FORMAT_TIME);
+
           GST_PUSH_LOCK (ogg);
           if (!ogg->pullmode && ogg->push_state == PUSH_LINEAR2) {
             /* if we are fast forwarding to the actual seek target,
@@ -977,14 +957,19 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
                 ", start_time %" GST_TIME_FORMAT,
                 GST_TIME_ARGS (ogg->push_seek_time_original_target),
                 GST_TIME_ARGS (start_time));
-            event =
-                gst_event_new_new_segment (FALSE, ogg->push_seek_rate,
-                GST_FORMAT_TIME, ogg->push_seek_time_original_target, -1,
-                ogg->push_seek_time_original_target);
+            segment.rate = ogg->push_seek_rate;
+            segment.start = ogg->push_seek_time_original_target;
+            segment.stop = -1;
+            segment.time = ogg->push_seek_time_original_target;
+            event = gst_event_new_segment (&segment);
             ogg->push_state = PUSH_PLAYING;
           } else {
-            event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
-                GST_FORMAT_TIME, start_time, chain->segment_stop, segment_time);
+            segment.rate = ogg->segment.rate;
+            segment.applied_rate = ogg->segment.applied_rate;
+            segment.start = start_time;
+            segment.stop = chain->segment_stop;
+            segment.time = segment_time;
+            event = gst_event_new_segment (&segment);
           }
           GST_PUSH_UNLOCK (ogg);
 
@@ -994,6 +979,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
         /* see if we have enough info to activate the chain, we have enough info
          * when all streams have a valid start time. */
         if (gst_ogg_demux_collect_chain_info (ogg, chain)) {
+          GstSegment segment;
 
           GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT,
               GST_TIME_ARGS (chain->segment_start));
@@ -1003,9 +989,13 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
               GST_TIME_ARGS (chain->begin_time));
 
           /* create the newsegment event we are going to send out */
-          event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
-              GST_FORMAT_TIME, chain->segment_start, chain->segment_stop,
-              chain->begin_time);
+          gst_segment_init (&segment, GST_FORMAT_TIME);
+          segment.rate = ogg->segment.rate;
+          segment.applied_rate = ogg->segment.applied_rate;
+          segment.start = chain->segment_start;
+          segment.stop = chain->segment_stop;
+          segment.time = chain->begin_time;
+          event = gst_event_new_segment (&segment);
         }
       }
 
@@ -1071,7 +1061,7 @@ gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets)
          * collecting headers and that we don't have exposed the pads yet */
         if (result == GST_FLOW_NOT_LINKED)
           break;
-        else if (result <= GST_FLOW_UNEXPECTED)
+        else if (result <= GST_FLOW_EOS)
           goto could_not_submit;
         break;
       default:
@@ -1696,12 +1686,11 @@ gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
   GST_DEBUG_OBJECT (chain->ogg,
       "creating new stream %08x in chain %p", serialno, chain);
 
-  name = g_strdup_printf ("serial_%08x", serialno);
+  name = g_strdup_printf ("src_%08x", serialno);
   ret = g_object_new (GST_TYPE_OGG_PAD, "name", name, NULL);
   g_free (name);
   /* we own this one */
-  gst_object_ref (ret);
-  gst_object_sink (ret);
+  gst_object_ref_sink (ret);
 
   GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
   gst_ogg_pad_mark_discont (ret);
@@ -1714,7 +1703,7 @@ gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
     goto init_failed;
 
   /* FIXME: either do something with it or remove it */
-  list = gst_tag_list_new ();
+  list = gst_tag_list_new_empty ();
   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
       NULL);
   gst_tag_list_free (list);
@@ -1723,6 +1712,7 @@ gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
       "created new ogg src %p for stream with serial %08x", ret, serialno);
 
   g_array_append_val (chain->streams, ret);
+  gst_pad_set_active (GST_PAD_CAST (ret), TRUE);
 
   return ret;
 
@@ -1770,7 +1760,7 @@ enum
 };
 
 static GstStaticPadTemplate ogg_demux_src_template_factory =
-GST_STATIC_PAD_TEMPLATE ("src_%d",
+GST_STATIC_PAD_TEMPLATE ("src_%08x",
     GST_PAD_SRC,
     GST_PAD_SOMETIMES,
     GST_STATIC_CAPS_ANY);
@@ -1789,42 +1779,38 @@ static GstFlowReturn gst_ogg_demux_read_chain (GstOggDemux * ogg,
 static GstFlowReturn gst_ogg_demux_read_end_chain (GstOggDemux * ogg,
     GstOggChain * chain);
 
-static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
 static void gst_ogg_demux_loop (GstOggPad * pad);
-static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad);
-static gboolean gst_ogg_demux_sink_activate_pull (GstPad * sinkpad,
-    gboolean active);
-static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad,
-    gboolean active);
+static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer);
+static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad,
+    GstObject * parent);
+static gboolean gst_ogg_demux_sink_activate_mode (GstPad * sinkpad,
+    GstObject * parent, GstPadMode mode, gboolean active);
 static GstStateChangeReturn gst_ogg_demux_change_state (GstElement * element,
     GstStateChange transition);
 
 static void gst_ogg_print (GstOggDemux * demux);
 
-GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT);
+#define gst_ogg_demux_parent_class parent_class
+G_DEFINE_TYPE (GstOggDemux, gst_ogg_demux, GST_TYPE_ELEMENT);
 
 static void
-gst_ogg_demux_base_init (gpointer g_class)
+gst_ogg_demux_class_init (GstOggDemuxClass * klass)
 {
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
-  gst_element_class_set_details_simple (element_class,
+  gst_element_class_set_details_simple (gstelement_class,
       "Ogg demuxer", "Codec/Demuxer",
       "demux ogg streams (info about ogg: http://xiph.org)",
       "Wim Taymans <wim@fluendo.com>");
 
-  gst_element_class_add_pad_template (element_class,
+  gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&ogg_demux_sink_template_factory));
-  gst_element_class_add_pad_template (element_class,
+  gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&ogg_demux_src_template_factory));
-}
-
-static void
-gst_ogg_demux_class_init (GstOggDemuxClass * klass)
-{
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
   gstelement_class->change_state = gst_ogg_demux_change_state;
   gstelement_class->send_event = gst_ogg_demux_receive_event;
@@ -1833,7 +1819,7 @@ gst_ogg_demux_class_init (GstOggDemuxClass * klass)
 }
 
 static void
-gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class)
+gst_ogg_demux_init (GstOggDemux * ogg)
 {
   /* create the sink pad */
   ogg->sinkpad =
@@ -1843,10 +1829,8 @@ gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class)
   gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_sink_event);
   gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain);
   gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate);
-  gst_pad_set_activatepull_function (ogg->sinkpad,
-      gst_ogg_demux_sink_activate_pull);
-  gst_pad_set_activatepush_function (ogg->sinkpad,
-      gst_ogg_demux_sink_activate_push);
+  gst_pad_set_activatemode_function (ogg->sinkpad,
+      gst_ogg_demux_sink_activate_mode);
   gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
 
   ogg->chain_lock = g_mutex_new ();
@@ -1897,12 +1881,12 @@ gst_ogg_demux_reset_streams (GstOggDemux * ogg)
 }
 
 static gboolean
-gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
+gst_ogg_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
   gboolean res;
   GstOggDemux *ogg;
 
-  ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
+  ogg = GST_OGG_DEMUX (parent);
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
@@ -1919,24 +1903,21 @@ gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
         gst_ogg_demux_reset_streams (ogg);
       }
       break;
-    case GST_EVENT_NEWSEGMENT:
+    case GST_EVENT_SEGMENT:
       GST_DEBUG_OBJECT (ogg, "got a new segment event");
       {
-        gboolean update;
-        GstFormat format;
-        gdouble rate, arate;
-        gint64 start, stop, time;
-
-        gst_event_parse_new_segment_full (event, &update, &rate, &arate,
-            &format, &start, &stop, &time);
-        if (format == GST_FORMAT_BYTES) {
+        GstSegment segment;
+
+        gst_event_copy_segment (event, &segment);
+
+        if (segment.format == GST_FORMAT_BYTES) {
           GST_PUSH_LOCK (ogg);
-          ogg->push_byte_offset = start;
-          ogg->push_last_seek_offset = start;
+          ogg->push_byte_offset = segment.start;
+          ogg->push_last_seek_offset = segment.start;
           GST_PUSH_UNLOCK (ogg);
         } else {
           GST_WARNING_OBJECT (ogg, "unexpected segment format: %s",
-              gst_format_get_name (format));
+              gst_format_get_name (segment.format));
         }
       }
       gst_event_unref (event);
@@ -1975,7 +1956,6 @@ gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
       res = gst_ogg_demux_send_event (ogg, event);
       break;
   }
-  gst_object_unref (ogg);
 
   return res;
 }
@@ -1984,15 +1964,12 @@ gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
 static GstFlowReturn
 gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
 {
-  gint size;
-  guint8 *data;
+  gsize size;
   gchar *oggbuffer;
   GstFlowReturn ret = GST_FLOW_OK;
 
-  size = GST_BUFFER_SIZE (buffer);
-  data = GST_BUFFER_DATA (buffer);
-
-  GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size);
+  size = gst_buffer_get_size (buffer);
+  GST_DEBUG_OBJECT (ogg, "submitting %" G_GSIZE_FORMAT " bytes", size);
   if (G_UNLIKELY (size == 0))
     goto done;
 
@@ -2000,7 +1977,8 @@ gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
   if (G_UNLIKELY (oggbuffer == NULL))
     goto no_buffer;
 
-  memcpy (oggbuffer, data, size);
+  gst_buffer_extract (buffer, 0, oggbuffer, size);
+
   if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0))
     goto write_failed;
 
@@ -2025,8 +2003,8 @@ no_buffer:
   }
 write_failed:
   {
-    GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
-        (NULL), ("failed to write %d bytes to the sync buffer", size));
+    GST_ELEMENT_ERROR (ogg, STREAM, DECODE, (NULL),
+        ("failed to write %" G_GSIZE_FORMAT " bytes to the sync buffer", size));
     ret = GST_FLOW_ERROR;
     goto done;
   }
@@ -2069,7 +2047,7 @@ gst_ogg_demux_get_data (GstOggDemux * ogg, gint64 end_offset)
   if (ret != GST_FLOW_OK)
     goto error;
 
-  ogg->read_offset += GST_BUFFER_SIZE (buffer);
+  ogg->read_offset += gst_buffer_get_size (buffer);
 
   ret = gst_ogg_demux_submit_buffer (ogg, buffer);
 
@@ -2084,7 +2062,7 @@ boundary_reached:
 eos:
   {
     GST_LOG_OBJECT (ogg, "reached EOS");
-    return GST_FLOW_UNEXPECTED;
+    return GST_FLOW_EOS;
   }
 error:
   {
@@ -2101,7 +2079,7 @@ error:
  * @offset will contain the offset the next page starts at when this function
  * returns GST_FLOW_OK.
  *
- * GST_FLOW_UNEXPECTED is returned on EOS.
+ * GST_FLOW_EOS is returned on EOS.
  *
  * GST_FLOW_LIMIT is returned when we did not find a page before the
  * boundary. If @boundary is -1, this is never returned.
@@ -2215,7 +2193,7 @@ gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
         break;
       }
       /* something went wrong */
-      if (ret == GST_FLOW_UNEXPECTED) {
+      if (ret == GST_FLOW_EOS) {
         new_offset = 0;
         GST_LOG_OBJECT (ogg, "got unexpected");
       } else if (ret != GST_FLOW_OK) {
@@ -2313,7 +2291,8 @@ gst_ogg_demux_set_header_on_caps (GstOggDemux * ogg, GstCaps * caps,
     ogg_packet *op = headers->data;
     g_assert (op);
     buffer = gst_buffer_new_and_alloc (op->bytes);
-    memcpy (GST_BUFFER_DATA (buffer), op->packet, op->bytes);
+    if (op->bytes)
+      gst_buffer_fill (buffer, 0, op->packet, op->bytes);
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
     g_value_init (&value, GST_TYPE_BUFFER);
     gst_value_take_buffer (&value, buffer);
@@ -2386,7 +2365,8 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
     gst_ogg_pad_mark_discont (pad);
     pad->last_ret = GST_FLOW_OK;
 
-    if (pad->map.is_skeleton || pad->added || GST_PAD_CAPS (pad) == NULL)
+    if (pad->map.is_skeleton || pad->added
+        || !gst_pad_has_current_caps (GST_PAD_CAST (pad)))
       continue;
 
     GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
@@ -2411,10 +2391,12 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
 
   /* FIXME, must be sent from the streaming thread */
   if (event) {
+    GstTagList *tags;
+
     gst_ogg_demux_send_event (ogg, event);
 
-    gst_element_found_tags (GST_ELEMENT_CAST (ogg),
-        gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Ogg", NULL));
+    tags = gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "Ogg", NULL);
+    gst_ogg_demux_send_event (ogg, gst_event_new_tag (tags));
   }
 
   GST_DEBUG_OBJECT (ogg, "starting chain");
@@ -2429,8 +2411,8 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
     /* FIXME also streaming thread */
     if (pad->map.taglist) {
       GST_DEBUG_OBJECT (ogg, "pushing tags");
-      gst_element_found_tags_for_pad (GST_ELEMENT_CAST (ogg),
-          GST_PAD_CAST (pad), pad->map.taglist);
+      gst_pad_push_event (GST_PAD_CAST (pad),
+          gst_event_new_tag (pad->map.taglist));
       pad->map.taglist = NULL;
     }
 
@@ -2650,7 +2632,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
   gint i, pending, len;
   gboolean first_parsed_page = TRUE;
 
-  position = segment->last_stop;
+  position = segment->position;
 
   /* first find the chain to search in */
   total = ogg->total_time;
@@ -2805,7 +2787,7 @@ done:
   if (keyframe) {
     if (segment->rate > 0.0)
       segment->time = keytarget;
-    segment->last_stop = keytarget - begintime;
+    segment->position = keytarget - begintime;
   }
 
   *rchain = chain;
@@ -2903,28 +2885,8 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
    * forever. */
   GST_PAD_STREAM_LOCK (ogg->sinkpad);
 
-  if (ogg->segment_running && !flush) {
-    /* create the segment event to close the current segment */
-    if ((chain = ogg->current_chain)) {
-      GstEvent *newseg;
-      gint64 chain_start = 0;
-
-      if (chain->segment_start != GST_CLOCK_TIME_NONE)
-        chain_start = chain->segment_start;
-
-      newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate,
-          GST_FORMAT_TIME, ogg->segment.start + chain_start,
-          ogg->segment.last_stop + chain_start, ogg->segment.time);
-      /* set the seqnum of the running segment */
-      gst_event_set_seqnum (newseg, ogg->seqnum);
-
-      /* send segment on old chain, FIXME, must be sent from streaming thread. */
-      gst_ogg_demux_send_event (ogg, newseg);
-    }
-  }
-
   if (event) {
-    gst_segment_set_seek (&ogg->segment, rate, format, flags,
+    gst_segment_do_seek (&ogg->segment, rate, format, flags,
         cur_type, cur, stop_type, stop, &update);
   }
 
@@ -2935,7 +2897,7 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
   /* we need to stop flushing on the srcpad as we're going to use it
    * next. We can do this as we have the STREAM lock now. */
   if (flush) {
-    tevent = gst_event_new_flush_stop ();
+    tevent = gst_event_new_flush_stop (TRUE);
     gst_event_set_seqnum (tevent, seqnum);
     gst_pad_push_event (ogg->sinkpad, tevent);
   }
@@ -2971,11 +2933,12 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
     GstEvent *event;
     gint64 stop;
     gint64 start;
-    gint64 last_stop, begin_time;
+    gint64 position, begin_time;
+    GstSegment segment;
 
     /* we have to send the flush to the old chain, not the new one */
     if (flush) {
-      tevent = gst_event_new_flush_stop ();
+      tevent = gst_event_new_flush_stop (TRUE);
       gst_event_set_seqnum (tevent, seqnum);
       gst_ogg_demux_send_event (ogg, tevent);
     }
@@ -3008,18 +2971,21 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
       stop = MIN (stop, chain->segment_stop);
     }
 
-    last_stop = ogg->segment.last_stop;
+    position = ogg->segment.position;
     if (chain->segment_start != GST_CLOCK_TIME_NONE)
-      last_stop += chain->segment_start;
+      position += chain->segment_start;
 
-    /* create the segment event we are going to send out */
-    if (ogg->segment.rate >= 0.0)
-      event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
-          ogg->segment.format, last_stop, stop, ogg->segment.time);
-    else
-      event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
-          ogg->segment.format, start, last_stop, ogg->segment.time);
+    gst_segment_copy_into (&ogg->segment, &segment);
 
+    /* create the segment event we are going to send out */
+    if (ogg->segment.rate >= 0.0) {
+      segment.start = position;
+      segment.stop = stop;
+    } else {
+      segment.start = start;
+      segment.stop = position;
+    }
+    event = gst_event_new_segment (&segment);
     gst_event_set_seqnum (event, seqnum);
 
     if (chain != ogg->current_chain) {
@@ -3039,13 +3005,12 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event)
       GstMessage *message;
 
       message = gst_message_new_segment_start (GST_OBJECT (ogg),
-          GST_FORMAT_TIME, ogg->segment.last_stop);
+          GST_FORMAT_TIME, ogg->segment.position);
       gst_message_set_seqnum (message, seqnum);
 
       gst_element_post_message (GST_ELEMENT (ogg), message);
     }
 
-    ogg->segment_running = TRUE;
     ogg->seqnum = seqnum;
     /* restart our task since it might have been stopped when we did the 
      * flush. */
@@ -3114,18 +3079,16 @@ gst_ogg_demux_check_duration_push (GstOggDemux * ogg, GstSeekFlags flags,
 
     GST_DEBUG_OBJECT (ogg, "Trying to find byte/time length");
     if ((peer = gst_pad_get_peer (ogg->sinkpad)) != NULL) {
-      GstFormat format = GST_FORMAT_BYTES;
       gint64 length;
       int res;
 
-      res = gst_pad_query_duration (peer, &format, &length);
+      res = gst_pad_query_duration (peer, GST_FORMAT_BYTES, &length);
       if (res && length > 0) {
         ogg->push_byte_length = length;
         GST_DEBUG_OBJECT (ogg,
             "File byte length %" G_GINT64_FORMAT, ogg->push_byte_length);
       }
-      format = GST_FORMAT_TIME;
-      res = gst_pad_query_duration (peer, &format, &length);
+      res = gst_pad_query_duration (peer, GST_FORMAT_TIME, &length);
       gst_object_unref (peer);
       if (res && length >= 0) {
         ogg->push_time_length = length;
@@ -3362,7 +3325,7 @@ gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
     gst_ogg_demux_seek (ogg, bisect);
     ret = gst_ogg_demux_get_next_page (ogg, &og, -1, &offset);
 
-    if (ret == GST_FLOW_UNEXPECTED) {
+    if (ret == GST_FLOW_EOS) {
       endsearched = bisect;
     } else if (ret == GST_FLOW_OK) {
       guint32 serial = ogg_page_serialno (&og);
@@ -3388,7 +3351,7 @@ gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
 
   gst_ogg_demux_seek (ogg, next);
   ret = gst_ogg_demux_read_chain (ogg, &nextchain);
-  if (ret == GST_FLOW_UNEXPECTED) {
+  if (ret == GST_FLOW_EOS) {
     nextchain = NULL;
     ret = GST_FLOW_OK;
     GST_LOG_OBJECT (ogg, "no next chain");
@@ -3438,7 +3401,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
 
     ret = gst_ogg_demux_get_next_page (ogg, &og, -1, NULL);
     if (ret != GST_FLOW_OK) {
-      if (ret == GST_FLOW_UNEXPECTED) {
+      if (ret == GST_FLOW_EOS) {
         GST_DEBUG_OBJECT (ogg, "Reached EOS, done reading end chain");
       } else {
         GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret);
@@ -3451,7 +3414,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
        * ignore it */
       if (!chain) {
         GST_WARNING_OBJECT (ogg, "No chain found, no Ogg data in stream ?");
-        ret = GST_FLOW_UNEXPECTED;
+        ret = GST_FLOW_EOS;
       }
       break;
     }
@@ -3476,7 +3439,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
     if (ret == GST_FLOW_OK) {
       GST_WARNING_OBJECT (ogg, "no chain was found");
       ret = GST_FLOW_ERROR;
-    } else if (ret != GST_FLOW_UNEXPECTED) {
+    } else if (ret != GST_FLOW_EOS) {
       GST_WARNING_OBJECT (ogg, "failed to read chain");
     } else {
       GST_DEBUG_OBJECT (ogg, "done reading chains");
@@ -3729,7 +3692,7 @@ gst_ogg_demux_collect_info (GstOggDemux * ogg)
 
     ogg->total_time += chain->total_time;
   }
-  gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time);
+  ogg->segment.duration = ogg->total_time;
 }
 
 /* find all the chains in the ogg file, this reads the first and
@@ -3741,7 +3704,6 @@ gst_ogg_demux_find_chains (GstOggDemux * ogg)
 {
   ogg_page og;
   GstPad *peer;
-  GstFormat format;
   gboolean res;
   guint32 serialno;
   GstOggChain *chain;
@@ -3752,8 +3714,7 @@ gst_ogg_demux_find_chains (GstOggDemux * ogg)
     goto no_peer;
 
   /* find length to read last page, we store this for later use. */
-  format = GST_FORMAT_BYTES;
-  res = gst_pad_query_duration (peer, &format, &ogg->length);
+  res = gst_pad_query_duration (peer, GST_FORMAT_BYTES, &ogg->length);
   gst_object_unref (peer);
   if (!res || ogg->length <= 0)
     goto no_length;
@@ -3852,13 +3813,17 @@ gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page)
     if (chain) {
       GstEvent *event;
       gint64 start = 0;
+      GstSegment segment;
 
       if (chain->segment_start != GST_CLOCK_TIME_NONE)
         start = chain->segment_start;
 
       /* create the newsegment event we are going to send out */
-      event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
-          GST_FORMAT_TIME, start, chain->segment_stop, chain->begin_time);
+      gst_segment_copy_into (&ogg->segment, &segment);
+      segment.start = start;
+      segment.stop = chain->segment_stop;
+      segment.time = chain->begin_time;
+      event = gst_event_new_segment (&segment);
       gst_event_set_seqnum (event, ogg->seqnum);
 
       GST_DEBUG_OBJECT (ogg,
@@ -3879,7 +3844,7 @@ gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page)
       if (ogg->pullmode)
         goto unknown_chain;
 
-      current_time = ogg->segment.last_stop;
+      current_time = ogg->segment.position;
 
       /* time of new chain is current time */
       chain_time = current_time;
@@ -3946,13 +3911,13 @@ unknown_chain:
  * the serialno, submit pages and packets to the oggpads
  */
 static GstFlowReturn
-gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
+gst_ogg_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 {
   GstOggDemux *ogg;
   gint ret = 0;
   GstFlowReturn result = GST_FLOW_OK;
 
-  ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
+  ogg = GST_OGG_DEMUX (parent);
 
   GST_DEBUG_OBJECT (ogg, "enter");
   result = gst_ogg_demux_submit_buffer (ogg, buffer);
@@ -4078,7 +4043,7 @@ gst_ogg_demux_loop_forward (GstOggDemux * ogg)
   if (ogg->offset == ogg->length) {
     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
         " == %" G_GINT64_FORMAT, ogg->offset, ogg->length);
-    ret = GST_FLOW_UNEXPECTED;
+    ret = GST_FLOW_EOS;
     goto done;
   }
 
@@ -4089,14 +4054,14 @@ gst_ogg_demux_loop_forward (GstOggDemux * ogg)
     goto done;
   }
 
-  ogg->offset += GST_BUFFER_SIZE (buffer);
+  ogg->offset += gst_buffer_get_size (buffer);
 
   if (G_UNLIKELY (ogg->newsegment)) {
     gst_ogg_demux_send_event (ogg, ogg->newsegment);
     ogg->newsegment = NULL;
   }
 
-  ret = gst_ogg_demux_chain (ogg->sinkpad, buffer);
+  ret = gst_ogg_demux_chain (ogg->sinkpad, GST_OBJECT_CAST (ogg), buffer);
   if (ret != GST_FLOW_OK) {
     GST_LOG_OBJECT (ogg, "Failed demux_chain");
     goto done;
@@ -4105,7 +4070,7 @@ gst_ogg_demux_loop_forward (GstOggDemux * ogg)
   /* check for the end of the segment */
   if (gst_ogg_demux_check_eos (ogg)) {
     GST_LOG_OBJECT (ogg, "got EOS");
-    ret = GST_FLOW_UNEXPECTED;
+    ret = GST_FLOW_EOS;
     goto done;
   }
 done:
@@ -4130,7 +4095,7 @@ gst_ogg_demux_loop_reverse (GstOggDemux * ogg)
   if (ogg->offset == 0) {
     GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
         " == 0", ogg->offset);
-    ret = GST_FLOW_UNEXPECTED;
+    ret = GST_FLOW_EOS;
     goto done;
   }
 
@@ -4153,7 +4118,7 @@ gst_ogg_demux_loop_reverse (GstOggDemux * ogg)
   /* check for the end of the segment */
   if (gst_ogg_demux_check_eos (ogg)) {
     GST_LOG_OBJECT (ogg, "got EOS");
-    ret = GST_FLOW_UNEXPECTED;
+    ret = GST_FLOW_EOS;
     goto done;
   }
 done:
@@ -4168,7 +4133,7 @@ gst_ogg_demux_sync_streams (GstOggDemux * ogg)
   guint i;
 
   chain = ogg->current_chain;
-  cur = ogg->segment.last_stop;
+  cur = ogg->segment.position;
   if (chain == NULL || cur == -1)
     return;
 
@@ -4178,18 +4143,24 @@ gst_ogg_demux_sync_streams (GstOggDemux * ogg)
     /* Theoretically, we should be doing this for all streams, but we're only
      * doing it for known-to-be-sparse streams at the moment in order not to
      * break things for wrongly-muxed streams (like we used to produce once) */
-    if (stream->map.is_sparse && stream->last_stop != GST_CLOCK_TIME_NONE) {
+    if (stream->map.is_sparse && stream->position != GST_CLOCK_TIME_NONE) {
 
       /* Does this stream lag? Random threshold of 2 seconds */
-      if (GST_CLOCK_DIFF (stream->last_stop, cur) > (2 * GST_SECOND)) {
+      if (GST_CLOCK_DIFF (stream->position, cur) > (2 * GST_SECOND)) {
         GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
             "advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (stream->last_stop), GST_TIME_ARGS (cur));
-        stream->last_stop = cur;
+            GST_TIME_ARGS (stream->position), GST_TIME_ARGS (cur));
+
+        stream->position = cur;
+
+#if 0
+        ogg->segment.base += cur - stream->position;
         /* advance stream time (FIXME: is this right, esp. time_pos?) */
         gst_pad_push_event (GST_PAD_CAST (stream),
             gst_event_new_new_segment (TRUE, ogg->segment.rate,
-                GST_FORMAT_TIME, stream->last_stop, -1, stream->last_stop));
+                ogg->segment.applied_rate,
+                GST_FORMAT_TIME, stream->position, -1, stream->position));
+#endif
       }
     }
   }
@@ -4267,10 +4238,9 @@ pause:
     GstEvent *event = NULL;
 
     GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason);
-    ogg->segment_running = FALSE;
     gst_pad_pause_task (ogg->sinkpad);
 
-    if (ret == GST_FLOW_UNEXPECTED) {
+    if (ret == GST_FLOW_EOS) {
       /* perform EOS logic */
       if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
         gint64 stop;
@@ -4293,7 +4263,7 @@ pause:
         GST_LOG_OBJECT (ogg, "Sending EOS, at end of stream");
         event = gst_event_new_eos ();
       }
-    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
+    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
       GST_ELEMENT_ERROR (ogg, STREAM, FAILED,
           (_("Internal data stream error.")),
           ("stream stopped, reason %s", reason));
@@ -4337,51 +4307,65 @@ gst_ogg_demux_clear_chains (GstOggDemux * ogg)
  * pull based.
  */
 static gboolean
-gst_ogg_demux_sink_activate (GstPad * sinkpad)
+gst_ogg_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
 {
-  if (gst_pad_check_pull_range (sinkpad)) {
-    GST_DEBUG_OBJECT (sinkpad, "activating pull");
-    return gst_pad_activate_pull (sinkpad, TRUE);
-  } else {
-    GST_DEBUG_OBJECT (sinkpad, "activating push");
-    return gst_pad_activate_push (sinkpad, TRUE);
+  GstQuery *query;
+  gboolean pull_mode;
+
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (sinkpad, query)) {
+    gst_query_unref (query);
+    goto activate_push;
   }
-}
 
-/* this function gets called when we activate ourselves in push mode.
- * We cannot seek (ourselves) in the stream */
-static gboolean
-gst_ogg_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
-{
-  GstOggDemux *ogg;
+  pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
+  gst_query_unref (query);
 
-  ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
+  if (!pull_mode)
+    goto activate_push;
 
-  ogg->pullmode = FALSE;
-  ogg->resync = FALSE;
+  GST_DEBUG_OBJECT (sinkpad, "activating pull");
+  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
 
-  return TRUE;
+activate_push:
+  {
+    GST_DEBUG_OBJECT (sinkpad, "activating push");
+    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+  }
 }
 
-/* this function gets called when we activate ourselves in pull mode.
- * We can perform  random access to the resource and we start a task
- * to start reading */
 static gboolean
-gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
+gst_ogg_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+    GstPadMode mode, gboolean active)
 {
+  gboolean res;
   GstOggDemux *ogg;
 
-  ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
+  ogg = GST_OGG_DEMUX (parent);
 
-  if (active) {
-    ogg->need_chains = TRUE;
-    ogg->pullmode = TRUE;
+  switch (mode) {
+    case GST_PAD_MODE_PUSH:
+      ogg->pullmode = FALSE;
+      ogg->resync = FALSE;
+      res = TRUE;
+      break;
+    case GST_PAD_MODE_PULL:
+      if (active) {
+        ogg->need_chains = TRUE;
+        ogg->pullmode = TRUE;
 
-    return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
-        sinkpad);
-  } else {
-    return gst_pad_stop_task (sinkpad);
+        res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
+            sinkpad);
+      } else {
+        res = gst_pad_stop_task (sinkpad);
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
   }
+  return res;
 }
 
 static GstStateChangeReturn
@@ -4401,7 +4385,6 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
       ogg_sync_reset (&ogg->sync);
       ogg->running = FALSE;
       ogg->bitrate = 0;
-      ogg->segment_running = FALSE;
       ogg->total_time = -1;
       GST_PUSH_LOCK (ogg);
       ogg->push_byte_offset = 0;
@@ -4419,7 +4402,7 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
       break;
   }
 
-  result = parent_class->change_state (element, transition);
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   switch (transition) {
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
@@ -4428,7 +4411,6 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
       gst_ogg_demux_clear_chains (ogg);
       GST_OBJECT_LOCK (ogg);
       ogg->running = FALSE;
-      ogg->segment_running = FALSE;
       GST_OBJECT_UNLOCK (ogg);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL: