adaptivedemux2: Refactor stream methods into the stream
authorJan Schmidt <jan@centricular.com>
Sat, 20 Aug 2022 18:31:53 +0000 (04:31 +1000)
committerJan Schmidt <jan@centricular.com>
Fri, 4 Nov 2022 17:00:31 +0000 (04:00 +1100)
Unlike the legacy elements, GstAdaptiveDemuxStream is a GObject now,
so a bunch of things that were actually stream methods on the
parent demux object can directly become stream methods now.

Move the stream class out to a header of its own.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3314>

subprojects/gst-plugins-good/ext/adaptivedemux2/dash/gstdashdemux.c
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.h [new file with mode: 0644]
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-types.h [new file with mode: 0644]
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c
subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h
subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c

index 691a31b..3820937 100644 (file)
@@ -351,18 +351,12 @@ static void gst_dash_demux_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static void gst_dash_demux_dispose (GObject * obj);
 
-/* GstAdaptiveDemux */
-static GstClockTime gst_dash_demux_get_duration (GstAdaptiveDemux * ademux);
-static gboolean gst_dash_demux_is_live (GstAdaptiveDemux * ademux);
-static void gst_dash_demux_reset (GstAdaptiveDemux * ademux);
-static gboolean gst_dash_demux_process_manifest (GstAdaptiveDemux * ademux,
-    GstBuffer * buf);
-static gboolean gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
+/* GstAdaptiveDemuxStream */
 static GstFlowReturn
 gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream);
-static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemux2Stream *
-    stream, gboolean forward, GstSeekFlags flags, GstClockTimeDiff ts,
-    GstClockTimeDiff * final_ts);
+static GstClockTime
+gst_dash_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream *
+    stream);
 static gboolean gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream
     * stream);
 static GstFlowReturn
@@ -371,25 +365,35 @@ static gboolean
 gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemux2Stream * stream);
 static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemux2Stream *
     stream, guint64 bitrate);
+static GstClockTime
+gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
+    stream);
+static GstFlowReturn
+gst_dash_demux_stream_data_received (GstAdaptiveDemux2Stream * stream,
+    GstBuffer * buffer);
+static gboolean gst_dash_demux_stream_fragment_start (GstAdaptiveDemux2Stream *
+    stream);
+static GstFlowReturn
+gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux2Stream * stream);
+static gboolean
+gst_dash_demux_stream_need_another_chunk (GstAdaptiveDemux2Stream * stream);
+
+/* GstAdaptiveDemux */
+static GstClockTime gst_dash_demux_get_duration (GstAdaptiveDemux * ademux);
+static gboolean gst_dash_demux_is_live (GstAdaptiveDemux * ademux);
+static void gst_dash_demux_reset (GstAdaptiveDemux * ademux);
+static gboolean gst_dash_demux_process_manifest (GstAdaptiveDemux * ademux,
+    GstBuffer * buf);
+static gboolean gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
+static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemux2Stream *
+    stream, gboolean forward, GstSeekFlags flags, GstClockTimeDiff ts,
+    GstClockTimeDiff * final_ts);
 static gint64 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux *
     demux);
 static GstFlowReturn gst_dash_demux_update_manifest_data (GstAdaptiveDemux *
     demux, GstBuffer * buf);
-static GstClockTime
-gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
-    stream);
 static void gst_dash_demux_advance_period (GstAdaptiveDemux * demux);
 static gboolean gst_dash_demux_has_next_period (GstAdaptiveDemux * demux);
-static GstFlowReturn gst_dash_demux_data_received (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
-static gboolean
-gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static GstFlowReturn
-gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static gboolean gst_dash_demux_need_another_chunk (GstAdaptiveDemux2Stream *
-    stream);
 
 /* GstDashDemux2 */
 static gboolean gst_dash_demux_setup_all_streams (GstDashDemux2 * demux);
@@ -464,8 +468,32 @@ static void
 gst_dash_demux_stream_class_init (GstDashDemux2StreamClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstAdaptiveDemux2StreamClass *adaptivedemux2stream_class =
+      GST_ADAPTIVE_DEMUX2_STREAM_CLASS (klass);
 
   gobject_class->finalize = gst_dash_demux_stream_finalize;
+
+  adaptivedemux2stream_class->update_fragment_info =
+      gst_dash_demux_stream_update_fragment_info;
+  adaptivedemux2stream_class->has_next_fragment =
+      gst_dash_demux_stream_has_next_fragment;
+  adaptivedemux2stream_class->advance_fragment =
+      gst_dash_demux_stream_advance_fragment;
+  adaptivedemux2stream_class->get_fragment_waiting_time =
+      gst_dash_demux_stream_get_fragment_waiting_time;
+  adaptivedemux2stream_class->select_bitrate =
+      gst_dash_demux_stream_select_bitrate;
+  adaptivedemux2stream_class->get_presentation_offset =
+      gst_dash_demux_stream_get_presentation_offset;
+
+  adaptivedemux2stream_class->start_fragment =
+      gst_dash_demux_stream_fragment_start;
+  adaptivedemux2stream_class->finish_fragment =
+      gst_dash_demux_stream_fragment_finished;
+  adaptivedemux2stream_class->data_received =
+      gst_dash_demux_stream_data_received;
+  adaptivedemux2stream_class->need_another_chunk =
+      gst_dash_demux_stream_need_another_chunk;
 }
 
 
@@ -547,11 +575,10 @@ gst_dash_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
 }
 
 static GstClockTime
-gst_dash_demux_get_presentation_offset (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_dash_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream)
 {
   GstDashDemux2Stream *dashstream = (GstDashDemux2Stream *) stream;
-  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (demux);
+  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
 
   return gst_mpd_client2_get_stream_presentation_offset (dashdemux->client,
       dashstream->index);
@@ -628,30 +655,12 @@ gst_dash_demux2_class_init (GstDashDemux2Class * klass)
 
   gstadaptivedemux_class->has_next_period = gst_dash_demux_has_next_period;
   gstadaptivedemux_class->advance_period = gst_dash_demux_advance_period;
-  gstadaptivedemux_class->stream_has_next_fragment =
-      gst_dash_demux_stream_has_next_fragment;
-  gstadaptivedemux_class->stream_advance_fragment =
-      gst_dash_demux_stream_advance_fragment;
-  gstadaptivedemux_class->stream_get_fragment_waiting_time =
-      gst_dash_demux_stream_get_fragment_waiting_time;
+
   gstadaptivedemux_class->stream_seek = gst_dash_demux_stream_seek;
-  gstadaptivedemux_class->stream_select_bitrate =
-      gst_dash_demux_stream_select_bitrate;
-  gstadaptivedemux_class->stream_update_fragment_info =
-      gst_dash_demux_stream_update_fragment_info;
   gstadaptivedemux_class->get_live_seek_range =
       gst_dash_demux_get_live_seek_range;
-  gstadaptivedemux_class->get_presentation_offset =
-      gst_dash_demux_get_presentation_offset;
   gstadaptivedemux_class->get_period_start_time =
       gst_dash_demux_get_period_start_time;
-
-  gstadaptivedemux_class->start_fragment = gst_dash_demux_stream_fragment_start;
-  gstadaptivedemux_class->finish_fragment =
-      gst_dash_demux_stream_fragment_finished;
-  gstadaptivedemux_class->data_received = gst_dash_demux_data_received;
-  gstadaptivedemux_class->need_another_chunk =
-      gst_dash_demux_need_another_chunk;
 }
 
 static void
@@ -1827,10 +1836,10 @@ gst_dash_demux_stream_get_target_time (GstDashDemux2 * dashdemux,
   GstClockTime deadline;
   GstClockTime upstream_earliest_time;
   GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
-  gdouble play_rate = gst_adaptive_demux_play_rate (stream->demux);
+  gdouble play_rate = gst_adaptive_demux_play_rate (demux);
   GstClockTime period_start = gst_dash_demux_get_period_start_time (demux);
   GstClockTime pts_offset =
-      gst_dash_demux_get_presentation_offset (demux, stream);
+      gst_dash_demux_stream_get_presentation_offset (stream);
 
   g_assert (min_skip > 0);
 
@@ -2706,10 +2715,9 @@ _gst_buffer_split (GstBuffer * buffer, gint offset, gsize size)
 }
 
 static gboolean
-gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_dash_demux_stream_fragment_start (GstAdaptiveDemux2Stream * stream)
 {
-  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (demux);
+  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
   GstDashDemux2Stream *dashstream = (GstDashDemux2Stream *) stream;
 
   GST_LOG_OBJECT (stream, "Actual position %" GST_TIME_FORMAT,
@@ -2725,7 +2733,7 @@ gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
    * buffer. We need offsets to be consistent between moof and mdat
    */
   if (dashstream->is_isobmff && dashdemux->allow_trickmode_key_units
-      && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (demux)
+      && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)
       && dashstream->active_stream->mimeType == GST_STREAM_VIDEO)
     stream->discont = TRUE;
 
@@ -2733,11 +2741,10 @@ gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
 }
 
 static GstFlowReturn
-gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux2Stream * stream)
 {
   GstClockTime consumed_duration;
-  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (demux);
+  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
   GstDashDemux2Stream *dashstream = (GstDashDemux2Stream *) stream;
 
   /* We need to mark every first buffer of a key unit as discont,
@@ -2747,7 +2754,7 @@ gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
    * buffer. We need offsets to be consistent between moof and mdat
    */
   if (dashstream->is_isobmff && dashdemux->allow_trickmode_key_units
-      && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (demux)
+      && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)
       && dashstream->active_stream->mimeType == GST_STREAM_VIDEO)
     stream->discont = TRUE;
 
@@ -2774,20 +2781,20 @@ gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
     consumed_duration =
         (stream->fragment.stream_time + stream->fragment.duration) -
         stream->current_position;
-    GST_LOG_OBJECT (demux, "Consumed duration after seeking: %"
+    GST_LOG_OBJECT (stream, "Consumed duration after seeking: %"
         GST_TIMEP_FORMAT, &consumed_duration);
   } else {
     consumed_duration = stream->fragment.duration;
   }
 
-  return gst_adaptive_demux2_stream_advance_fragment (demux, stream,
+  return gst_adaptive_demux2_stream_advance_fragment (stream,
       consumed_duration);
 }
 
 static gboolean
-gst_dash_demux_need_another_chunk (GstAdaptiveDemux2Stream * stream)
+gst_dash_demux_stream_need_another_chunk (GstAdaptiveDemux2Stream * stream)
 {
-  GstDashDemux2 *dashdemux = (GstDashDemux2 *) stream->demux;
+  GstDashDemux2 *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
   GstAdaptiveDemux *demux = stream->demux;
   GstDashDemux2Stream *dashstream = (GstDashDemux2Stream *) stream;
   gboolean playing_forward = (demux->segment.rate > 0.0);
@@ -3371,9 +3378,9 @@ gst_dash_demux_find_sync_samples (GstAdaptiveDemux * demux,
 
 
 static GstFlowReturn
-gst_dash_demux_handle_isobmff (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_dash_demux_stream_handle_isobmff (GstAdaptiveDemux2Stream * stream)
 {
+  GstAdaptiveDemux *demux = stream->demux;
   GstDashDemux2Stream *dash_stream = (GstDashDemux2Stream *) stream;
   GstFlowReturn ret = GST_FLOW_OK;
   GstBuffer *buffer;
@@ -3527,22 +3534,22 @@ gst_dash_demux_handle_isobmff (GstAdaptiveDemux * demux,
 
   if (sidx_advance) {
     ret =
-        gst_adaptive_demux2_stream_advance_fragment (demux, stream,
+        gst_adaptive_demux2_stream_advance_fragment (stream,
         SIDX_CURRENT_ENTRY (dash_stream)->duration);
     if (ret != GST_FLOW_OK)
       return ret;
 
     /* If we still have data available, recurse and use it up if possible */
     if (gst_adapter_available (dash_stream->adapter) > 0)
-      return gst_dash_demux_handle_isobmff (demux, stream);
+      return gst_dash_demux_stream_handle_isobmff (stream);
   }
 
   return ret;
 }
 
 static GstFlowReturn
-gst_dash_demux_data_received (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer)
+gst_dash_demux_stream_data_received (GstAdaptiveDemux2Stream * stream,
+    GstBuffer * buffer)
 {
   GstDashDemux2Stream *dash_stream = (GstDashDemux2Stream *) stream;
   GstFlowReturn ret = GST_FLOW_OK;
@@ -3574,7 +3581,7 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
 
   if (dash_stream->is_isobmff || stream->downloading_index) {
     /* SIDX index is also ISOBMMF */
-    ret = gst_dash_demux_handle_isobmff (demux, stream);
+    ret = gst_dash_demux_stream_handle_isobmff (stream);
   } else if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
     gsize available;
 
@@ -3622,7 +3629,7 @@ gst_dash_demux_data_received (GstAdaptiveDemux * demux,
         if (has_next) {
           GstFlowReturn new_ret;
           new_ret =
-              gst_adaptive_demux2_stream_advance_fragment (demux, stream,
+              gst_adaptive_demux2_stream_advance_fragment (stream,
               SIDX_CURRENT_ENTRY (dash_stream)->duration);
 
           /* only overwrite if it was OK before */
index cc62325..630ba71 100644 (file)
 #ifndef _GST_ADAPTIVE_DEMUX_PRIVATE_H_
 #define _GST_ADAPTIVE_DEMUX_PRIVATE_H_
 
+#include <gst/gst.h>
 #include <gst/base/gstadapter.h>
 #include <gst/base/gstflowcombiner.h>
 
+#include "gstadaptivedemux-types.h"
+#include "gstadaptivedemux.h"
+#include "gstadaptivedemuxutils.h"
+
+G_BEGIN_DECLS
+
 #define NUM_LOOKBACK_FRAGMENTS 3
 #define MAX_DOWNLOAD_ERROR_COUNT 3
 
@@ -166,10 +173,8 @@ GstFlowReturn gst_adaptive_demux_update_manifest (GstAdaptiveDemux *demux);
 void gst_adaptive_demux2_stream_wants_manifest_update (GstAdaptiveDemux * demux);
 
 void gst_adaptive_demux2_stream_parse_error (GstAdaptiveDemux2Stream *stream, GError * err);
-GstClockTime gst_adaptive_demux2_stream_get_fragment_waiting_time (GstAdaptiveDemux *
-    demux, GstAdaptiveDemux2Stream * stream);
-GstClockTime gst_adaptive_demux2_stream_get_presentation_offset (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
+GstClockTime gst_adaptive_demux2_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream * stream);
+GstClockTime gst_adaptive_demux2_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream);
 GstClockTime gst_adaptive_demux_get_period_start_time (GstAdaptiveDemux * demux);
 
 gboolean gst_adaptive_demux_is_live (GstAdaptiveDemux * demux);
@@ -177,10 +182,7 @@ gboolean gst_adaptive_demux_is_live (GstAdaptiveDemux * demux);
 void gst_adaptive_demux2_stream_on_manifest_update (GstAdaptiveDemux2Stream * stream);
 void gst_adaptive_demux2_stream_on_output_space_available (GstAdaptiveDemux2Stream *stream);
 
-gboolean gst_adaptive_demux2_stream_has_next_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-GstFlowReturn gst_adaptive_demux2_stream_update_fragment_info (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
+gboolean gst_adaptive_demux2_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream);
 GstFlowReturn gst_adaptive_demux2_stream_seek (GstAdaptiveDemux * demux,
     GstAdaptiveDemux2Stream * stream, gboolean forward, GstSeekFlags flags,
     GstClockTimeDiff ts, GstClockTimeDiff * final_ts);
@@ -193,6 +195,7 @@ gboolean gst_adaptive_demux2_stream_is_selected_locked (GstAdaptiveDemux2Stream
 gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux);
 void gst_adaptive_demux_advance_period (GstAdaptiveDemux * demux);
 
+GstFlowReturn gst_adaptive_demux2_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream);
 void gst_adaptive_demux2_stream_stop (GstAdaptiveDemux2Stream * stream);
 
 gboolean gst_adaptive_demux_handle_lost_sync (GstAdaptiveDemux * demux);
@@ -240,4 +243,6 @@ GstFlowReturn            gst_adaptive_demux_period_combine_stream_flows (GstAdap
 gboolean                 gst_adaptive_demux_period_has_pending_tracks (GstAdaptiveDemuxPeriod * period);
 void      gst_adaptive_demux_period_check_input_wakeup_locked (GstAdaptiveDemuxPeriod * period, GstClockTimeDiff current_output_position);
 
+G_END_DECLS
+
 #endif
index 11cdcbe..60eaceb 100644 (file)
@@ -27,7 +27,7 @@
 #include "config.h"
 #endif
 
-#include "gstadaptivedemux.h"
+#include "gstadaptivedemux-stream.h"
 #include "gstadaptivedemux-private.h"
 
 #include <glib/gi18n-lib.h>
@@ -38,6 +38,18 @@ GST_DEBUG_CATEGORY_EXTERN (adaptivedemux2_debug);
 
 static void gst_adaptive_demux2_stream_finalize (GObject * object);
 static void gst_adaptive_demux2_stream_error (GstAdaptiveDemux2Stream * stream);
+static GstFlowReturn
+gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux2Stream *
+    stream, GstBuffer * buffer);
+static GstFlowReturn
+gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux2Stream *
+    stream);
+
+guint64
+gst_adaptive_demux2_stream_update_current_bitrate (GstAdaptiveDemux2Stream *
+    stream);
+static void gst_adaptive_demux2_stream_update_track_ids (GstAdaptiveDemux2Stream
+    * stream);
 
 #define gst_adaptive_demux2_stream_parent_class parent_class
 G_DEFINE_ABSTRACT_TYPE (GstAdaptiveDemux2Stream, gst_adaptive_demux2_stream,
@@ -49,6 +61,9 @@ gst_adaptive_demux2_stream_class_init (GstAdaptiveDemux2StreamClass * klass)
   GObjectClass *gobject_class = (GObjectClass *) klass;
 
   gobject_class->finalize = gst_adaptive_demux2_stream_finalize;
+
+  klass->data_received = gst_adaptive_demux2_stream_data_received_default;
+  klass->finish_fragment = gst_adaptive_demux2_stream_finish_fragment_default;
 }
 
 static GType tsdemux_type = 0;
@@ -255,10 +270,10 @@ schedule_another_chunk (GstAdaptiveDemux2Stream * stream)
 }
 
 static void
-drain_inactive_tracks (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+drain_inactive_tracks (GstAdaptiveDemux2Stream * stream)
 {
   GList *iter;
+  GstAdaptiveDemux *demux = stream->demux;
 
   TRACKS_LOCK (demux);
   for (iter = stream->tracks; iter; iter = iter->next) {
@@ -278,8 +293,8 @@ static void
 gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
     stream, GstFlowReturn ret, GError * err)
 {
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (stream->demux);
-  GstAdaptiveDemux *demux = stream->demux;
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
 
   GST_DEBUG_OBJECT (stream,
       "%s download finish: %d %s - err: %p", uritype (stream), ret,
@@ -313,12 +328,12 @@ gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
   if (ret == GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC) {
     /* We lost sync, seek back to live and return */
     GST_WARNING_OBJECT (stream, "Lost sync when downloading");
-    gst_adaptive_demux_handle_lost_sync (demux);
+    gst_adaptive_demux_handle_lost_sync (stream->demux);
     return;
   } else if (ret == GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT) {
     /* The sub-class wants to stop the fragment immediately */
     stream->fragment.finished = TRUE;
-    ret = klass->finish_fragment (demux, stream);
+    ret = klass->finish_fragment (stream);
 
     GST_DEBUG_OBJECT (stream, "finish_fragment ret %d %s", ret,
         gst_flow_get_name (ret));
@@ -331,7 +346,7 @@ gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
       || !klass->need_another_chunk (stream)
       || stream->fragment.chunk_size == 0) {
     stream->fragment.finished = TRUE;
-    ret = klass->finish_fragment (stream->demux, stream);
+    ret = klass->finish_fragment (stream);
 
     GST_DEBUG_OBJECT (stream, "finish_fragment ret %d %s", ret,
         gst_flow_get_name (ret));
@@ -343,7 +358,7 @@ gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
 
   /* For HLS, we might be enqueueing data into tracks that aren't
    * selected. Drain those ones out */
-  drain_inactive_tracks (stream->demux, stream);
+  drain_inactive_tracks (stream);
 
   /* Now that we've called finish_fragment we can clear these flags the
    * sub-class might have checked */
@@ -387,7 +402,7 @@ gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
 
   GST_LOG_OBJECT (stream, "Scheduling next_download() call");
   stream->pending_cb_id =
-      gst_adaptive_demux_loop_call (demux->priv->scheduler_task,
+      gst_adaptive_demux_loop_call (stream->demux->priv->scheduler_task,
       (GSourceFunc) gst_adaptive_demux2_stream_next_download,
       gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
 }
@@ -414,13 +429,16 @@ gst_adaptive_demux2_stream_parse_error (GstAdaptiveDemux2Stream * stream,
 }
 
 static void
-gst_adaptive_demux2_stream_prepare_segment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, gboolean first_and_live)
+gst_adaptive_demux2_stream_prepare_segment (GstAdaptiveDemux2Stream * stream,
+    gboolean first_and_live)
 {
+  GstAdaptiveDemux *demux = stream->demux;
   GstClockTime period_start = gst_adaptive_demux_get_period_start_time (demux);
   GstClockTime offset =
-      gst_adaptive_demux2_stream_get_presentation_offset (demux, stream);
+      gst_adaptive_demux2_stream_get_presentation_offset (stream);
 
+  /* FIXME: Add a helper function to retrieve the demuxer segment
+   * using the SEGMENT_LOCK */
   stream->parse_segment = demux->segment;
 
   /* The demuxer segment is just built from seek events, but for each stream
@@ -478,8 +496,9 @@ gst_adaptive_demux2_stream_prepare_segment (GstAdaptiveDemux * demux,
    * the segment time and base as calculated by the second case would be
    * equivalent.
    */
-  GST_DEBUG_OBJECT (demux, "Using demux segment %" GST_SEGMENT_FORMAT,
-      &demux->segment);
+  GST_DEBUG_OBJECT (stream, "Using demux segment %" GST_SEGMENT_FORMAT,
+      &stream->parse_segment);
+
   GST_DEBUG_OBJECT (demux,
       "period_start: %" GST_TIME_FORMAT " offset: %" GST_TIME_FORMAT,
       GST_TIME_ARGS (period_start), GST_TIME_ARGS (offset));
@@ -542,7 +561,7 @@ update_buffer_pts_and_demux_position_locked (GstAdaptiveDemux * demux,
 
   if (GST_CLOCK_STIME_IS_VALID (pos)) {
     GstClockTime offset =
-        gst_adaptive_demux2_stream_get_presentation_offset (demux, stream);
+        gst_adaptive_demux2_stream_get_presentation_offset (stream);
 
     pos += offset;
 
@@ -574,8 +593,7 @@ gst_adaptive_demux2_stream_push_buffer (GstAdaptiveDemux2Stream * stream,
   GList *pending_events = NULL;
 
   if (stream->compute_segment) {
-    gst_adaptive_demux2_stream_prepare_segment (demux, stream,
-        stream->first_and_live);
+    gst_adaptive_demux2_stream_prepare_segment (stream, stream->first_and_live);
     stream->compute_segment = FALSE;
     stream->first_and_live = FALSE;
   }
@@ -711,7 +729,8 @@ gst_adaptive_demux2_stream_parse_buffer (GstAdaptiveDemux2Stream * stream,
     GstBuffer * buffer)
 {
   GstAdaptiveDemux *demux = stream->demux;
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
   GstFlowReturn ret = GST_FLOW_OK;
 
   /* do not make any changes if the stream is cancelled */
@@ -728,7 +747,7 @@ gst_adaptive_demux2_stream_parse_buffer (GstAdaptiveDemux2Stream * stream,
    * including the *actual* fragment ! */
   if (stream->starting_fragment) {
     stream->starting_fragment = FALSE;
-    if (klass->start_fragment != NULL && !klass->start_fragment (demux, stream))
+    if (klass->start_fragment != NULL && !klass->start_fragment (stream))
       return GST_FLOW_ERROR;
   }
 
@@ -738,7 +757,7 @@ gst_adaptive_demux2_stream_parse_buffer (GstAdaptiveDemux2Stream * stream,
       "Received %s buffer of size %" G_GSIZE_FORMAT, uritype (stream),
       gst_buffer_get_size (buffer));
 
-  ret = klass->data_received (demux, stream, buffer);
+  ret = klass->data_received (stream, buffer);
 
   if (ret != GST_FLOW_OK) {
     GST_DEBUG_OBJECT (stream, "data_received returned %s",
@@ -759,7 +778,7 @@ gst_adaptive_demux2_stream_parse_buffer (GstAdaptiveDemux2Stream * stream,
       GST_DEBUG_OBJECT (stream, "Pushing EOS to parser");
 
       /* TODO push this on all pads */
-      gst_event_set_seqnum (eos, stream->demux->priv->segment_seqnum);
+      gst_event_set_seqnum (eos, demux->priv->segment_seqnum);
       gst_pad_send_event (stream->parsebin_sink, eos);
       ret = GST_FLOW_ERROR;
 
@@ -1177,7 +1196,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
           || last_status_code / 100 == 5)) {
     /* 4xx/5xx */
     /* if current position is before available start, switch to next */
-    if (!gst_adaptive_demux2_stream_has_next_fragment (demux, stream))
+    if (!gst_adaptive_demux2_stream_has_next_fragment (stream))
       goto flushing;
 
     if (live) {
@@ -1195,7 +1214,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
 
         GST_DEBUG_OBJECT (demux, "Calling update_fragment_info");
 
-        ret = gst_adaptive_demux2_stream_update_fragment_info (demux, stream);
+        ret = gst_adaptive_demux2_stream_update_fragment_info (stream);
         GST_DEBUG_OBJECT (stream, "update_fragment_info ret: %s",
             gst_flow_get_name (ret));
 
@@ -1205,8 +1224,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
       } else if (demux->segment.position > range_stop) {
         /* wait a bit to be in range, we don't have any locks at that point */
         GstClockTime wait_time =
-            gst_adaptive_demux2_stream_get_fragment_waiting_time (demux,
-            stream);
+            gst_adaptive_demux2_stream_get_fragment_waiting_time (stream);
         if (wait_time > 0) {
           GST_DEBUG_OBJECT (stream,
               "Download waiting for %" GST_TIME_FORMAT,
@@ -1230,7 +1248,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
       gst_adaptive_demux2_stream_handle_playlist_eos (stream);
       return;
     }
-  } else if (!gst_adaptive_demux2_stream_has_next_fragment (demux, stream)) {
+  } else if (!gst_adaptive_demux2_stream_has_next_fragment (stream)) {
     /* If this is the last fragment, consider failures EOS and not actual
      * errors. Due to rounding errors in the durations, the last fragment
      * might not actually exist */
@@ -1421,7 +1439,8 @@ static GstFlowReturn
 gst_adaptive_demux2_stream_download_fragment (GstAdaptiveDemux2Stream * stream)
 {
   GstAdaptiveDemux *demux = stream->demux;
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
   gchar *url = NULL;
 
   /* FIXME :  */
@@ -1760,7 +1779,7 @@ gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream)
     case GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE:
       /* Get information about the fragment to download */
       GST_DEBUG_OBJECT (demux, "Calling update_fragment_info");
-      ret = gst_adaptive_demux2_stream_update_fragment_info (demux, stream);
+      ret = gst_adaptive_demux2_stream_update_fragment_info (stream);
       GST_DEBUG_OBJECT (stream,
           "Fragment info update result: %d %s", ret, gst_flow_get_name (ret));
 
@@ -1795,7 +1814,7 @@ gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream)
     /* wait for live fragments to be available */
     if (live) {
       GstClockTime wait_time =
-          gst_adaptive_demux2_stream_get_fragment_waiting_time (demux, stream);
+          gst_adaptive_demux2_stream_get_fragment_waiting_time (stream);
       if (wait_time > 0) {
         GST_DEBUG_OBJECT (stream,
             "Download waiting for %" GST_TIME_FORMAT,
@@ -1967,12 +1986,12 @@ gst_adaptive_demux2_stream_next_download (GstAdaptiveDemux2Stream * stream)
 static gboolean
 gst_adaptive_demux2_stream_can_start (GstAdaptiveDemux2Stream * stream)
 {
-  GstAdaptiveDemux *demux = stream->demux;
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
 
-  if (!klass->stream_can_start)
+  if (!klass->can_start)
     return TRUE;
-  return klass->stream_can_start (demux, stream);
+  return klass->can_start (stream);
 }
 
 /**
@@ -2096,3 +2115,492 @@ gst_adaptive_demux2_stream_is_selected (GstAdaptiveDemux2Stream * stream)
 
   return ret;
 }
+
+/* Called from the scheduler task */
+GstClockTime
+gst_adaptive_demux2_stream_get_presentation_offset (GstAdaptiveDemux2Stream *
+    stream)
+{
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+
+  if (klass->get_presentation_offset == NULL)
+    return 0;
+
+  return klass->get_presentation_offset (stream);
+}
+
+GstFlowReturn
+gst_adaptive_demux2_stream_update_fragment_info (GstAdaptiveDemux2Stream *
+    stream)
+{
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (klass->update_fragment_info != NULL, GST_FLOW_ERROR);
+
+  /* Make sure the sub-class will update bitrate, or else
+   * we will later */
+  stream->fragment.finished = FALSE;
+
+  GST_LOG_OBJECT (stream, "position %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (stream->current_position));
+
+  ret = klass->update_fragment_info (stream);
+
+  GST_LOG_OBJECT (stream, "ret:%s uri:%s",
+      gst_flow_get_name (ret), stream->fragment.uri);
+  if (ret == GST_FLOW_OK) {
+    GST_LOG_OBJECT (stream,
+        "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
+        GST_STIME_ARGS (stream->fragment.stream_time),
+        GST_TIME_ARGS (stream->fragment.duration));
+    GST_LOG_OBJECT (stream,
+        "range start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT,
+        stream->fragment.range_start, stream->fragment.range_end);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux2Stream *
+    stream, GstBuffer * buffer)
+{
+  return gst_adaptive_demux2_stream_push_buffer (stream, buffer);
+}
+
+static GstFlowReturn
+gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux2Stream *
+    stream)
+{
+  /* No need to advance, this isn't a real fragment */
+  if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
+    return GST_FLOW_OK;
+
+  return gst_adaptive_demux2_stream_advance_fragment (stream,
+      stream->fragment.duration);
+}
+
+/* must be called from the scheduler */
+gboolean
+gst_adaptive_demux2_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream)
+{
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+  gboolean ret = TRUE;
+
+  if (klass->has_next_fragment)
+    ret = klass->has_next_fragment (stream);
+
+  return ret;
+}
+
+static gboolean
+gst_adaptive_demux2_stream_select_bitrate (GstAdaptiveDemux *
+    demux, GstAdaptiveDemux2Stream * stream, guint64 bitrate)
+{
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+
+  if (klass->select_bitrate)
+    return klass->select_bitrate (stream, bitrate);
+  return FALSE;
+}
+
+GstClockTime
+gst_adaptive_demux2_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
+    stream)
+{
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+
+  if (klass->get_fragment_waiting_time)
+    return klass->get_fragment_waiting_time (stream);
+  return 0;
+}
+
+/* must be called from the scheduler */
+/* Called from: the ::finish_fragment() handlers when an *actual* fragment is
+ * done
+ *
+ * @duration: Is the duration of the advancement starting from
+ * stream->current_position which might not be the fragment duration after a
+ * seek.
+ */
+GstFlowReturn
+gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux2Stream * stream,
+    GstClockTime duration)
+{
+  if (stream->last_ret != GST_FLOW_OK)
+    return stream->last_ret;
+
+  GstAdaptiveDemux2StreamClass *klass =
+      GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+  GstAdaptiveDemux *demux = stream->demux;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  g_assert (klass->advance_fragment != NULL);
+
+  GST_LOG_OBJECT (stream,
+      "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
+      GST_STIME_ARGS (stream->fragment.stream_time), GST_TIME_ARGS (duration));
+
+  stream->download_error_count = 0;
+  g_clear_error (&stream->last_error);
+
+#if 0
+  /* FIXME - url has no indication of byte ranges for subsegments */
+  /* FIXME: Reenable statistics sending? */
+  gst_element_post_message (GST_ELEMENT_CAST (demux),
+      gst_message_new_element (GST_OBJECT_CAST (demux),
+          gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
+              "manifest-uri", G_TYPE_STRING,
+              demux->manifest_uri, "uri", G_TYPE_STRING,
+              stream->fragment.uri, "fragment-start-time",
+              GST_TYPE_CLOCK_TIME, stream->download_start_time,
+              "fragment-stop-time", GST_TYPE_CLOCK_TIME,
+              gst_util_get_timestamp (), "fragment-size", G_TYPE_UINT64,
+              stream->download_total_bytes, "fragment-download-time",
+              GST_TYPE_CLOCK_TIME, stream->last_download_time, NULL)));
+#endif
+
+  /* Don't update to the end of the segment if in reverse playback */
+  GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
+  if (GST_CLOCK_TIME_IS_VALID (duration) && demux->segment.rate > 0) {
+    stream->parse_segment.position += duration;
+    stream->current_position += duration;
+
+    GST_DEBUG_OBJECT (stream,
+        "stream position now %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (stream->current_position));
+  }
+  GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
+
+  /* When advancing with a non 1.0 rate on live streams, we need to check
+   * the live seeking range again to make sure we can still advance to
+   * that position */
+  if (demux->segment.rate != 1.0 && gst_adaptive_demux_is_live (demux)) {
+    if (!gst_adaptive_demux2_stream_in_live_seek_range (demux, stream))
+      ret = GST_FLOW_EOS;
+    else
+      ret = klass->advance_fragment (stream);
+  } else if (gst_adaptive_demux_is_live (demux)
+      || gst_adaptive_demux2_stream_has_next_fragment (stream)) {
+    ret = klass->advance_fragment (stream);
+  } else {
+    ret = GST_FLOW_EOS;
+  }
+
+  stream->download_start_time =
+      GST_TIME_AS_USECONDS (gst_adaptive_demux2_get_monotonic_time (demux));
+
+  /* Always check if we need to switch bitrate on OK, or when live
+   * (it's normal to have EOS on advancing in live when we hit the
+   * end of the manifest) */
+  if (ret == GST_FLOW_OK || gst_adaptive_demux_is_live (demux)) {
+    GST_DEBUG_OBJECT (stream, "checking if stream requires bitrate change");
+    if (gst_adaptive_demux2_stream_select_bitrate (demux, stream,
+            gst_adaptive_demux2_stream_update_current_bitrate (stream))) {
+      GST_DEBUG_OBJECT (stream, "Bitrate changed. Returning FLOW_SWITCH");
+      stream->need_header = TRUE;
+      ret = (GstFlowReturn) GST_ADAPTIVE_DEMUX_FLOW_SWITCH;
+    }
+  }
+
+  stream->last_ret = ret;
+  return stream->last_ret;
+}
+
+/* TRACKS_LOCK held */
+static GstAdaptiveDemuxTrack *
+gst_adaptive_demux2_stream_find_track_of_type (GstAdaptiveDemux2Stream * stream,
+    GstStreamType stream_type)
+{
+  GList *iter;
+
+  for (iter = stream->tracks; iter; iter = iter->next) {
+    GstAdaptiveDemuxTrack *track = iter->data;
+
+    if (track->type == stream_type)
+      return track;
+  }
+
+  return NULL;
+}
+
+/* TRACKS lock held */
+static void
+gst_adaptive_demux2_stream_update_track_ids (GstAdaptiveDemux2Stream * stream)
+{
+  guint i;
+
+  GST_DEBUG_OBJECT (stream, "Updating track information from collection");
+
+  for (i = 0; i < gst_stream_collection_get_size (stream->stream_collection);
+      i++) {
+    GstStream *gst_stream =
+        gst_stream_collection_get_stream (stream->stream_collection, i);
+    GstStreamType stream_type = gst_stream_get_stream_type (gst_stream);
+    GstAdaptiveDemuxTrack *track;
+
+    if (stream_type == GST_STREAM_TYPE_UNKNOWN)
+      continue;
+    track = gst_adaptive_demux2_stream_find_track_of_type (stream, stream_type);
+    if (!track) {
+      GST_DEBUG_OBJECT (stream,
+          "We don't have an existing track to handle stream %" GST_PTR_FORMAT,
+          gst_stream);
+      continue;
+    }
+
+    if (track->upstream_stream_id)
+      g_free (track->upstream_stream_id);
+    track->upstream_stream_id =
+        g_strdup (gst_stream_get_stream_id (gst_stream));
+  }
+
+}
+
+static gboolean
+tags_have_language_info (GstTagList * tags)
+{
+  const gchar *language = NULL;
+
+  if (tags == NULL)
+    return FALSE;
+
+  if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_CODE, 0,
+          &language))
+    return TRUE;
+  if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_NAME, 0,
+          &language))
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+can_handle_collection (GstAdaptiveDemux2Stream * stream,
+    GstStreamCollection * collection)
+{
+  guint i;
+  guint nb_audio, nb_video, nb_text;
+  gboolean have_audio_languages = TRUE;
+  gboolean have_text_languages = TRUE;
+
+  nb_audio = nb_video = nb_text = 0;
+
+  for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
+    GstStream *gst_stream = gst_stream_collection_get_stream (collection, i);
+    GstTagList *tags = gst_stream_get_tags (gst_stream);
+
+    GST_DEBUG_OBJECT (stream,
+        "Internal collection stream #%d %" GST_PTR_FORMAT, i, gst_stream);
+    switch (gst_stream_get_stream_type (gst_stream)) {
+      case GST_STREAM_TYPE_AUDIO:
+        have_audio_languages &= tags_have_language_info (tags);
+        nb_audio++;
+        break;
+      case GST_STREAM_TYPE_VIDEO:
+        nb_video++;
+        break;
+      case GST_STREAM_TYPE_TEXT:
+        have_text_languages &= tags_have_language_info (tags);
+        nb_text++;
+        break;
+      default:
+        break;
+    }
+  }
+
+  /* Check that we either have at most 1 of each track type, or that
+   * we have language tags for each to tell which is which */
+  if (nb_video > 1 ||
+      (nb_audio > 1 && !have_audio_languages) ||
+      (nb_text > 1 && !have_text_languages)) {
+    GST_WARNING
+        ("Collection can't be handled (nb_audio:%d, nb_video:%d, nb_text:%d)",
+        nb_audio, nb_video, nb_text);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Called from the demuxer when it receives a GstStreamCollection on the bus
+ * for this stream. */
+/* TRACKS lock held */
+gboolean
+gst_adaptive_demux2_stream_handle_collection (GstAdaptiveDemux2Stream * stream,
+    GstStreamCollection * collection, gboolean * had_pending_tracks)
+{
+  g_assert (had_pending_tracks != NULL);
+
+  /* Check whether the collection is "sane" or not.
+   *
+   * In the context of adaptive streaming, we can only handle multiplexed
+   * content where the output sub-streams can be matched reliably to the various
+   * tracks. That is, only a single stream of each type, or if there are
+   * multiple audio/subtitle tracks, they can be differentiated by language
+   * (and possibly in the future by codec).
+   */
+  if (!can_handle_collection (stream, collection)) {
+    return FALSE;
+  }
+
+  /* Store the collection on the stream */
+  gst_object_replace ((GstObject **) & stream->stream_collection,
+      (GstObject *) collection);
+
+  /* If stream is marked as having pending_tracks, ask the subclass to
+   * handle that and create the tracks now */
+  if (stream->pending_tracks) {
+    GstAdaptiveDemux2StreamClass *klass =
+        GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
+    g_assert (klass->create_tracks);
+    klass->create_tracks (stream);
+    stream->pending_tracks = FALSE;
+    *had_pending_tracks = TRUE;
+  } else {
+    g_assert (stream->tracks);
+
+    /* Now we should have assigned tracks, match them to the
+     * collection and update the pending upstream stream_id
+     * for each of them based on the collection information. */
+    gst_adaptive_demux2_stream_update_track_ids (stream);
+  }
+
+  return TRUE;
+}
+
+static guint64
+_update_average_bitrate (GstAdaptiveDemux2Stream * stream, guint64 new_bitrate)
+{
+  gint index = stream->moving_index % NUM_LOOKBACK_FRAGMENTS;
+
+  stream->moving_bitrate -= stream->fragment_bitrates[index];
+  stream->fragment_bitrates[index] = new_bitrate;
+  stream->moving_bitrate += new_bitrate;
+
+  stream->moving_index += 1;
+
+  if (stream->moving_index > NUM_LOOKBACK_FRAGMENTS)
+    return stream->moving_bitrate / NUM_LOOKBACK_FRAGMENTS;
+  return stream->moving_bitrate / stream->moving_index;
+}
+
+guint64
+gst_adaptive_demux2_stream_update_current_bitrate (GstAdaptiveDemux2Stream *
+    stream)
+{
+  guint64 average_bitrate;
+  guint64 fragment_bitrate;
+  guint connection_speed, min_bitrate, max_bitrate, target_download_rate;
+
+  fragment_bitrate = stream->last_bitrate;
+  GST_DEBUG_OBJECT (stream, "Download bitrate is : %" G_GUINT64_FORMAT " bps",
+      fragment_bitrate);
+
+  average_bitrate = _update_average_bitrate (stream, fragment_bitrate);
+
+  GST_INFO_OBJECT (stream,
+      "last fragment bitrate was %" G_GUINT64_FORMAT, fragment_bitrate);
+  GST_INFO_OBJECT (stream,
+      "Last %u fragments average bitrate is %" G_GUINT64_FORMAT,
+      NUM_LOOKBACK_FRAGMENTS, average_bitrate);
+
+  /* Conservative approach, make sure we don't upgrade too fast */
+  stream->current_download_rate = MIN (average_bitrate, fragment_bitrate);
+
+  /* For the video stream, update the demuxer reported download
+   * rate. FIXME: Move all bandwidth estimation to the
+   * download helper and make it the demuxer's responsibility
+   * to select the right set of things to download within
+   * that bandwidth */
+  GstAdaptiveDemux *demux = stream->demux;
+  GST_OBJECT_LOCK (demux);
+
+  /* If this is stream containing our video, update the overall demuxer
+   * reported bitrate and notify, to give the application a
+   * chance to choose a new connection-bitrate */
+  if ((stream->stream_type & GST_STREAM_TYPE_VIDEO) != 0) {
+    demux->current_download_rate = stream->current_download_rate;
+    GST_OBJECT_UNLOCK (demux);
+    g_object_notify (G_OBJECT (demux), "current-bandwidth");
+    GST_OBJECT_LOCK (demux);
+  }
+
+  connection_speed = demux->connection_speed;
+  min_bitrate = demux->min_bitrate;
+  max_bitrate = demux->max_bitrate;
+  GST_OBJECT_UNLOCK (demux);
+
+  if (connection_speed) {
+    GST_LOG_OBJECT (stream, "connection-speed is set to %u kbps, using it",
+        connection_speed / 1000);
+    return connection_speed;
+  }
+
+  /* No explicit connection_speed, so choose the new variant to use as a
+   * fraction of the measured download rate */
+  target_download_rate =
+      CLAMP (stream->current_download_rate, 0,
+      G_MAXUINT) * demux->bandwidth_target_ratio;
+
+  GST_DEBUG_OBJECT (stream, "Bitrate after target ratio limit (%0.2f): %u",
+      demux->bandwidth_target_ratio, target_download_rate);
+
+#if 0
+  /* Debugging code, modulate the bitrate every few fragments */
+  {
+    static guint ctr = 0;
+    if (ctr % 3 == 0) {
+      GST_INFO_OBJECT (stream, "Halving reported bitrate for debugging");
+      target_download_rate /= 2;
+    }
+    ctr++;
+  }
+#endif
+
+  if (min_bitrate > 0 && target_download_rate < min_bitrate) {
+    target_download_rate = min_bitrate;
+    GST_LOG_OBJECT (stream, "Bitrate adjusted due to min-bitrate : %u bits/s",
+        min_bitrate);
+  }
+
+  if (max_bitrate > 0 && target_download_rate > max_bitrate) {
+    target_download_rate = max_bitrate;
+    GST_LOG_OBJECT (stream, "Bitrate adjusted due to max-bitrate : %u bits/s",
+        max_bitrate);
+  }
+
+  GST_DEBUG_OBJECT (stream, "Returning target download rate of %u bps",
+      target_download_rate);
+
+  return target_download_rate;
+}
+
+void
+gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f)
+{
+  g_free (f->uri);
+  f->uri = NULL;
+  f->range_start = 0;
+  f->range_end = -1;
+
+  g_free (f->header_uri);
+  f->header_uri = NULL;
+  f->header_range_start = 0;
+  f->header_range_end = -1;
+
+  g_free (f->index_uri);
+  f->index_uri = NULL;
+  f->index_range_start = 0;
+  f->index_range_end = -1;
+
+  f->stream_time = GST_CLOCK_STIME_NONE;
+  f->duration = GST_CLOCK_TIME_NONE;
+  f->finished = FALSE;
+}
diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.h
new file mode 100644 (file)
index 0000000..7049b10
--- /dev/null
@@ -0,0 +1,348 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *   Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * Copyright (C) 2021-2022 Centricular Ltd
+ *   Author: Edward Hervey <edward@centricular.com>
+ *   Author: Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _GST_ADAPTIVE_DEMUX_STREAM_H_
+#define _GST_ADAPTIVE_DEMUX_STREAM_H_
+
+#include <gst/gst.h>
+#include "gstadaptivedemux-types.h"
+#include "downloadrequest.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ADAPTIVE_DEMUX2_STREAM \
+  (gst_adaptive_demux2_stream_get_type())
+#define GST_ADAPTIVE_DEMUX2_STREAM(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX2_STREAM,GstAdaptiveDemux2Stream))
+#define GST_ADAPTIVE_DEMUX2_STREAM_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADAPTIVE_DEMUX2_STREAM,GstAdaptiveDemux2StreamClass))
+#define GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_ADAPTIVE_DEMUX2_STREAM,GstAdaptiveDemux2StreamClass))
+#define GST_IS_ADAPTIVE_DEMUX2_STREAM(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADAPTIVE_DEMUX2_STREAM))
+#define GST_IS_ADAPTIVE_DEMUX2_STREAM_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADAPTIVE_DEMUX2_STREAM))
+#define GST_ADAPTIVE_DEMUX2_STREAM_CAST(obj) ((GstAdaptiveDemux2Stream *)obj)
+
+
+#define GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER(obj) (((GstAdaptiveDemux2Stream *) (obj))->need_header)
+
+typedef enum _GstAdaptiveDemux2StreamState GstAdaptiveDemux2StreamState;
+
+typedef struct _GstAdaptiveDemux2StreamFragment GstAdaptiveDemux2StreamFragment;
+
+struct _GstAdaptiveDemux2StreamFragment
+{
+  /* The period-local stream time for the given fragment. */
+  GstClockTimeDiff stream_time;
+  GstClockTime duration;
+
+  gchar *uri;
+  gint64 range_start;
+  gint64 range_end;
+
+  /* when chunked downloading is used, may be be updated need_another_chunk() */
+  gint chunk_size;
+
+  /* when headers are needed */
+  gchar *header_uri;
+  gint64 header_range_start;
+  gint64 header_range_end;
+
+  /* when index is needed */
+  gchar *index_uri;
+  gint64 index_range_start;
+  gint64 index_range_end;
+
+  gboolean finished;
+};
+
+enum _GstAdaptiveDemux2StreamState {
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED, /* Stream was stopped */
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART, /* Stream stopped but needs restart logic */
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_LIVE,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS,
+  GST_ADAPTIVE_DEMUX2_STREAM_STATE_ERRORED
+};
+
+struct _GstAdaptiveDemux2StreamClass
+{
+  GstObjectClass parent_class;
+
+  /**
+   * update_fragment_info:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * Requests the stream to set the information about the current fragment to its
+   * current fragment struct
+   *
+   * Returns: #GST_FLOW_OK in success, #GST_FLOW_ERROR on error and #GST_FLOW_EOS
+   *          if there is no fragment.
+   */
+  GstFlowReturn (*update_fragment_info) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * finish_fragment:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * Notifies the subclass that a fragment download was finished.
+   * It can be used to cleanup internal state after a fragment and
+   * also push any pending data before moving to the next fragment.
+   */
+  GstFlowReturn (*finish_fragment) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * data_received:
+   * @stream: #GstAdaptiveDemux2Stream
+   * @buffer: #GstBuffer
+   *
+   * Notifies the subclass that a fragment chunk was downloaded. The subclass
+   * can look at the data and modify/push data as desired.
+   *
+   * Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
+   */
+  GstFlowReturn (*data_received) (GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
+
+  gboolean      (*has_next_fragment)  (GstAdaptiveDemux2Stream * stream);
+  GstFlowReturn (*advance_fragment) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * can_start:
+   * @stream: a #GstAdaptiveDemux2Stream
+   *
+   * Called before starting a @stream. sub-classes can return %FALSE if more
+   * information is required before it can be started. Sub-classes will have to
+   * call gst_adaptive_demux2_stream_start() when the stream should be started.
+   */
+  gboolean      (*can_start) (GstAdaptiveDemux2Stream *stream);
+
+  /**
+   * create_tracks:
+   * @stream: A #GstAdaptiveDemux2Stream
+   *
+   * Called whenever the base class collected a @collection on a @stream which has
+   * pending tracks to be created. Subclasses should override this if they
+   * create streams without tracks.
+   *
+   * * create the various tracks by analyzing the @stream stream_collection
+   * * Set the track upstream_stream_id to the corresponding stream_id from the collection
+   */
+  void  (*create_tracks) (GstAdaptiveDemux2Stream *stream);
+
+  /**
+   * need_another_chunk:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * If chunked downloading is used (chunk_size != 0) this is called once a
+   * chunk is finished to decide whether more has to be downloaded or not.
+   * May update chunk_size to a different value
+   */
+  gboolean      (*need_another_chunk) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * select_bitrate:
+   * @stream: #GstAdaptiveDemux2Stream
+   * @bitrate: the bitrate to select (in bytes per second)
+   *
+   * The stream should try to select the bitrate that is the greater, but not
+   * greater than the requested bitrate. If it needs a codec change it should
+   * create the new stream using gst_adaptive_demux2_stream_new(). If it only
+   * needs a caps change it should set the new caps using
+   * gst_adaptive_demux2_stream_set_caps().
+   *
+   * Returns: %TRUE if the stream changed bitrate, %FALSE otherwise
+   */
+  gboolean      (*select_bitrate) (GstAdaptiveDemux2Stream * stream, guint64 bitrate);
+
+  /**
+   * get_fragment_waiting_time:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * For live streams, requests how much time should be waited before starting
+   * to download the fragment. This is useful to avoid downloading a fragment that
+   * isn't available yet.
+   *
+   * Returns: The waiting time in as a #GstClockTime
+   */
+  GstClockTime (*get_fragment_waiting_time) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * start_fragment:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * Notifies the subclass that the given stream is starting the download
+   * of a new fragment. Can be used to reset/init internal state that is
+   * needed before each fragment, like decryption engines.
+   *
+   * Returns: %TRUE if successful.
+   */
+  gboolean      (*start_fragment) (GstAdaptiveDemux2Stream * stream);
+
+  /**
+   * get_presentation_offset:
+   * @stream: #GstAdaptiveDemux2Stream
+   *
+   * Gets the delay to apply to @stream.
+   *
+   * Return: a #GstClockTime representing the (positive) time offset to apply to
+   * @stream.
+   */
+  GstClockTime (*get_presentation_offset) (GstAdaptiveDemux2Stream *stream);
+};
+
+struct _GstAdaptiveDemux2Stream
+{
+  GstObject object;
+
+  /* FIXME : transition to gstobject->parent */
+  GstAdaptiveDemux *demux;
+
+  /* The period to which the stream belongs, set when adding the stream to the
+   * demuxer */
+  GstAdaptiveDemuxPeriod *period;
+
+  /* The tracks this stream targets */
+  GList *tracks;
+
+  /* The internal parsebin, forward data to track */
+  GstElement *parsebin;
+  GstPad *parsebin_sink;
+
+  gulong pad_added_id, pad_removed_id;
+
+  GstSegment parse_segment;
+
+  /* TRUE if the current stream GstSegment should be sent downstream */
+  gboolean send_segment;
+  /* TRUE if the stream GstSegment requires recalculation (from demuxer
+     segment) */
+  gboolean compute_segment;
+  /* first_and_live applies to compute_segment */
+  gboolean first_and_live;
+
+  /* When restarting, what is the target position (in demux segment) to
+   * begin at */
+  GstClockTime start_position;
+
+  /* Track the current position (in demux segment) of the current fragment */
+  GstClockTime current_position;
+
+  GstCaps *pending_caps;
+  GstTagList *pending_tags;
+
+  GList *pending_events;
+
+  GstFlowReturn last_ret;
+  GError *last_error;
+
+  gboolean discont;
+
+  /* download tooling */
+  gboolean need_header;
+  gboolean need_index;
+
+  gboolean downloading_header;
+  gboolean downloading_index;
+
+  /* persistent, reused download request for fragment data */
+  DownloadRequest *download_request;
+
+  GstAdaptiveDemux2StreamState state;
+  guint pending_cb_id;
+  gboolean download_active;
+  /* The (global output) time at which this stream should be woken
+   * to download more input */
+  GstClockTimeDiff next_input_wakeup_time;
+
+  guint last_status_code;
+
+  gboolean pending_tracks; /* if we need to discover tracks dynamically for this stream */
+  gboolean download_finished;
+
+  gboolean starting_fragment;
+  gboolean first_fragment_buffer;
+  gint64 download_start_time;
+  gint64 download_total_bytes;
+  gint64 download_end_offset;
+  guint64 current_download_rate;
+
+  /* bitrate of the previous fragment (pre-queue2) */
+  guint64 last_bitrate;
+
+  /* Total last download time, from request to completion */
+  GstClockTime last_download_time;
+
+  /* Average for the last fragments */
+  guint64 moving_bitrate;
+  guint moving_index;
+  guint64 *fragment_bitrates;
+
+  GstAdaptiveDemux2StreamFragment fragment;
+
+  guint download_error_count;
+
+  /* Last collection provided by parsebin */
+  GstStreamCollection *stream_collection;
+
+  /* OR'd set of stream types in this stream */
+  GstStreamType stream_type;
+
+  /* The buffering threshold recommended by the subclass */
+  GstClockTime recommended_buffering_threshold;
+};
+
+GType    gst_adaptive_demux2_stream_get_type (void);
+
+void gst_adaptive_demux2_stream_start (GstAdaptiveDemux2Stream * stream);
+
+void gst_adaptive_demux2_stream_queue_event (GstAdaptiveDemux2Stream * stream,
+                                            GstEvent * event);
+
+gboolean gst_adaptive_demux2_stream_is_selected (GstAdaptiveDemux2Stream *stream);
+gboolean gst_adaptive_demux2_stream_is_running (GstAdaptiveDemux2Stream * stream);
+
+void gst_adaptive_demux2_stream_set_caps (GstAdaptiveDemux2Stream * stream,
+                                         GstCaps * caps);
+
+void gst_adaptive_demux2_stream_set_tags (GstAdaptiveDemux2Stream * stream,
+                                         GstTagList * tags);
+
+GstFlowReturn gst_adaptive_demux2_stream_push_buffer (GstAdaptiveDemux2Stream * stream,
+                                                     GstBuffer * buffer);
+
+GstFlowReturn gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux2Stream * stream,
+                                                          GstClockTime duration);
+
+gboolean gst_adaptive_demux2_stream_handle_collection (GstAdaptiveDemux2Stream *stream,
+    GstStreamCollection *collection, gboolean *had_pending_tracks);
+
+void gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f);
+
+G_END_DECLS
+
+#endif
diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-types.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-types.h
new file mode 100644 (file)
index 0000000..8c0fda3
--- /dev/null
@@ -0,0 +1,55 @@
+/* GStreamer
+ *
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *   Author: Thiago Santos <thiagoss@osg.samsung.com>
+ *
+ * Copyright (C) 2021-2022 Centricular Ltd
+ *   Author: Edward Hervey <edward@centricular.com>
+ *   Author: Jan Schmidt <jan@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_ADAPTIVE_DEMUX_TYPES_H_
+#define _GST_ADAPTIVE_DEMUX_TYPES_H_
+
+G_BEGIN_DECLS
+
+typedef struct _GstAdaptiveDemux2StreamClass GstAdaptiveDemux2StreamClass;
+typedef struct _GstAdaptiveDemux2Stream GstAdaptiveDemux2Stream;
+typedef struct _GstAdaptiveDemuxTrack GstAdaptiveDemuxTrack;
+typedef struct _GstAdaptiveDemuxPeriod GstAdaptiveDemuxPeriod;
+typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
+typedef struct _GstAdaptiveDemuxClass GstAdaptiveDemuxClass;
+
+#define GST_TYPE_ADAPTIVE_DEMUX \
+  (gst_adaptive_demux_ng_get_type())
+#define GST_ADAPTIVE_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemux))
+#define GST_ADAPTIVE_DEMUX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
+#define GST_ADAPTIVE_DEMUX_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
+#define GST_IS_ADAPTIVE_DEMUX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADAPTIVE_DEMUX))
+#define GST_IS_ADAPTIVE_DEMUX_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADAPTIVE_DEMUX))
+#define GST_ADAPTIVE_DEMUX_CAST(obj) ((GstAdaptiveDemux *)obj)
+
+G_END_DECLS
+
+#endif
+
index 261bf06..07b8ffd 100644 (file)
@@ -229,8 +229,6 @@ static void gst_adaptive_demux_reset (GstAdaptiveDemux * demux);
 static gboolean gst_adaptive_demux_prepare_streams (GstAdaptiveDemux * demux,
     gboolean first_and_live);
 
-static gboolean gst_adaptive_demux2_stream_select_bitrate (GstAdaptiveDemux *
-    demux, GstAdaptiveDemux2Stream * stream, guint64 bitrate);
 static GstFlowReturn
 gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux);
 
@@ -242,19 +240,6 @@ static void gst_adaptive_demux_start_manifest_update_task (GstAdaptiveDemux *
 static void gst_adaptive_demux_start_tasks (GstAdaptiveDemux * demux);
 static void gst_adaptive_demux_stop_tasks (GstAdaptiveDemux * demux,
     gboolean stop_updates);
-static GstFlowReturn
-gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
-static GstFlowReturn
-gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static GstFlowReturn
-gst_adaptive_demux2_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstClockTime duration);
-
-static void
-gst_adaptive_demux2_stream_update_tracks (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
 
 static gboolean
 gst_adaptive_demux_requires_periodical_playlist_update_default (GstAdaptiveDemux
@@ -532,19 +517,15 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass)
   gst_element_class_add_static_pad_template (gstelement_class,
       &gst_adaptive_demux_subtitlesrc_template);
 
-
   gstelement_class->change_state = gst_adaptive_demux_change_state;
   gstelement_class->query = gst_adaptive_demux_query;
   gstelement_class->send_event = gst_adaptive_demux_send_event;
 
   gstbin_class->handle_message = gst_adaptive_demux_handle_message;
 
-  klass->data_received = gst_adaptive_demux2_stream_data_received_default;
-  klass->finish_fragment = gst_adaptive_demux2_stream_finish_fragment_default;
   klass->update_manifest = gst_adaptive_demux_update_manifest_default;
   klass->requires_periodical_playlist_update =
       gst_adaptive_demux_requires_periodical_playlist_update_default;
-  klass->stream_update_tracks = gst_adaptive_demux2_stream_update_tracks;
   gst_type_mark_as_plugin_api (GST_TYPE_ADAPTIVE_DEMUX, 0);
 }
 
@@ -1468,123 +1449,6 @@ find_stream_for_element_locked (GstAdaptiveDemux * demux, GstObject * o)
   return NULL;
 }
 
-/* TRACKS_LOCK held */
-static GstAdaptiveDemuxTrack *
-gst_adaptive_demux2_stream_find_track_of_type (GstAdaptiveDemux2Stream * stream,
-    GstStreamType stream_type)
-{
-  GList *iter;
-
-  for (iter = stream->tracks; iter; iter = iter->next) {
-    GstAdaptiveDemuxTrack *track = iter->data;
-
-    if (track->type == stream_type)
-      return track;
-  }
-
-  return NULL;
-}
-
-/* MANIFEST and TRACKS lock held */
-static void
-gst_adaptive_demux2_stream_update_tracks (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  guint i;
-
-  GST_DEBUG_OBJECT (stream, "Updating track information from collection");
-
-  for (i = 0; i < gst_stream_collection_get_size (stream->stream_collection);
-      i++) {
-    GstStream *gst_stream =
-        gst_stream_collection_get_stream (stream->stream_collection, i);
-    GstStreamType stream_type = gst_stream_get_stream_type (gst_stream);
-    GstAdaptiveDemuxTrack *track;
-
-    if (stream_type == GST_STREAM_TYPE_UNKNOWN)
-      continue;
-    track = gst_adaptive_demux2_stream_find_track_of_type (stream, stream_type);
-    if (!track) {
-      GST_DEBUG_OBJECT (stream,
-          "We don't have an existing track to handle stream %" GST_PTR_FORMAT,
-          gst_stream);
-      continue;
-    }
-
-    if (track->upstream_stream_id)
-      g_free (track->upstream_stream_id);
-    track->upstream_stream_id =
-        g_strdup (gst_stream_get_stream_id (gst_stream));
-  }
-
-}
-
-static gboolean
-tags_have_language_info (GstTagList * tags)
-{
-  const gchar *language = NULL;
-
-  if (tags == NULL)
-    return FALSE;
-
-  if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_CODE, 0,
-          &language))
-    return TRUE;
-  if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_NAME, 0,
-          &language))
-    return TRUE;
-
-  return FALSE;
-}
-
-static gboolean
-can_handle_collection (GstAdaptiveDemux2Stream * stream,
-    GstStreamCollection * collection)
-{
-  guint i;
-  guint nb_audio, nb_video, nb_text;
-  gboolean have_audio_languages = TRUE;
-  gboolean have_text_languages = TRUE;
-
-  nb_audio = nb_video = nb_text = 0;
-
-  for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
-    GstStream *gst_stream = gst_stream_collection_get_stream (collection, i);
-    GstTagList *tags = gst_stream_get_tags (gst_stream);
-
-    GST_DEBUG_OBJECT (stream,
-        "Internal collection stream #%d %" GST_PTR_FORMAT, i, gst_stream);
-    switch (gst_stream_get_stream_type (gst_stream)) {
-      case GST_STREAM_TYPE_AUDIO:
-        have_audio_languages &= tags_have_language_info (tags);
-        nb_audio++;
-        break;
-      case GST_STREAM_TYPE_VIDEO:
-        nb_video++;
-        break;
-      case GST_STREAM_TYPE_TEXT:
-        have_text_languages &= tags_have_language_info (tags);
-        nb_text++;
-        break;
-      default:
-        break;
-    }
-  }
-
-  /* Check that we either have at most 1 of each track type, or that
-   * we have language tags for each to tell which is which */
-  if (nb_video > 1 ||
-      (nb_audio > 1 && !have_audio_languages) ||
-      (nb_text > 1 && !have_text_languages)) {
-    GST_WARNING
-        ("Collection can't be handled (nb_audio:%d, nb_video:%d, nb_text:%d)",
-        nb_audio, nb_video, nb_text);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
 static void
 gst_adaptive_demux_handle_stream_collection_msg (GstAdaptiveDemux * demux,
     GstMessage * msg)
@@ -1606,60 +1470,38 @@ gst_adaptive_demux_handle_stream_collection_msg (GstAdaptiveDemux * demux,
   if (!collection)
     goto beach;
 
-  /* Check whether the collection is "sane" or not.
-   *
-   * In the context of adaptive streaming, we can only handle multiplexed
-   * content that provides at most one stream of valid types (audio, video,
-   * text). Without this we cannot reliably match the output of this multiplex
-   * to the various tracks.
-   *
-   * FIXME : In the future and *IF* we encounter such streams, we could envision
-   * supporting multiple streams of the same type if, and only if, they have
-   * tags that allow differentiating them (ex: languages).
-   */
-  if (!can_handle_collection (stream, collection)) {
+  TRACKS_LOCK (demux);
+
+  if (!gst_adaptive_demux2_stream_handle_collection (stream, collection,
+          &pending_tracks_activated)) {
+    TRACKS_UNLOCK (demux);
+
     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
         (_("Stream format can't be handled")),
         ("The streams provided by the multiplex are ambiguous"));
     goto beach;
   }
 
-  /* Store the collection on the stream */
-  gst_object_replace ((GstObject **) & stream->stream_collection,
-      (GstObject *) collection);
-
-  /* IF there are pending tracks, ask the subclass to handle that */
-  if (stream->pending_tracks) {
-    GstAdaptiveDemuxClass *demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-    g_assert (demux_class->stream_update_tracks);
-    demux_class->stream_update_tracks (demux, stream);
-    TRACKS_LOCK (demux);
-    stream->pending_tracks = FALSE;
-    pending_tracks_activated = TRUE;
+  if (pending_tracks_activated) {
+    /* If pending tracks were handled, then update the demuxer collection */
     if (gst_adaptive_demux_update_collection (demux, demux->input_period) &&
-        demux->input_period == demux->output_period)
+        demux->input_period == demux->output_period) {
       gst_adaptive_demux_post_collection (demux);
-  } else {
-    g_assert (stream->tracks);
-    TRACKS_LOCK (demux);
-    /* If we already have assigned tracks, update the pending upstream stream_id
-     * for each of them based on the collection information. */
-    gst_adaptive_demux2_stream_update_tracks (demux, stream);
-  }
+    }
+
+    /* If we discovered pending tracks and we no longer have any, we can ensure
+     * selected tracks are started */
+    if (!gst_adaptive_demux_period_has_pending_tracks (demux->input_period)) {
+      GList *iter = demux->input_period->streams;
+      for (; iter; iter = iter->next) {
+        GstAdaptiveDemux2Stream *new_stream = iter->data;
 
-  /* If we discovered pending tracks and we no longer have any, we can ensure
-   * selected tracks are started */
-  if (pending_tracks_activated
-      && !gst_adaptive_demux_period_has_pending_tracks (demux->input_period)) {
-    GList *iter = demux->input_period->streams;
-    for (; iter; iter = iter->next) {
-      GstAdaptiveDemux2Stream *new_stream = iter->data;
-
-      /* The stream that posted this collection was already started. If a
-       * different stream is now selected, start it */
-      if (stream != new_stream
-          && gst_adaptive_demux2_stream_is_selected_locked (new_stream))
-        gst_adaptive_demux2_stream_start (new_stream);
+        /* The stream that posted this collection was already started. If a
+         * different stream is now selected, start it */
+        if (stream != new_stream
+            && gst_adaptive_demux2_stream_is_selected_locked (new_stream))
+          gst_adaptive_demux2_stream_start (new_stream);
+      }
     }
   }
   TRACKS_UNLOCK (demux);
@@ -1743,21 +1585,6 @@ gst_adaptive_demux_handle_message (GstBin * bin, GstMessage * msg)
 
 /* must be called with manifest_lock taken */
 GstClockTime
-gst_adaptive_demux2_stream_get_presentation_offset (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  GstAdaptiveDemuxClass *klass;
-
-  klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-
-  if (klass->get_presentation_offset == NULL)
-    return 0;
-
-  return klass->get_presentation_offset (demux, stream);
-}
-
-/* must be called with manifest_lock taken */
-GstClockTime
 gst_adaptive_demux_get_period_start_time (GstAdaptiveDemux * demux)
 {
   GstAdaptiveDemuxClass *klass;
@@ -1813,7 +1640,7 @@ gst_adaptive_demux_prepare_streams (GstAdaptiveDemux * demux,
       /* TODO we only need the first timestamp, maybe create a simple function to
        * get the current PTS of a fragment ? */
       GST_DEBUG_OBJECT (stream, "Calling update_fragment_info");
-      gst_adaptive_demux2_stream_update_fragment_info (demux, stream);
+      gst_adaptive_demux2_stream_update_fragment_info (stream);
 
       GST_DEBUG_OBJECT (stream,
           "Got stream time %" GST_STIME_FORMAT,
@@ -3008,130 +2835,6 @@ gst_adaptive_demux2_stream_queue_event (GstAdaptiveDemux2Stream * stream,
   stream->pending_events = g_list_append (stream->pending_events, event);
 }
 
-static guint64
-_update_average_bitrate (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, guint64 new_bitrate)
-{
-  gint index = stream->moving_index % NUM_LOOKBACK_FRAGMENTS;
-
-  stream->moving_bitrate -= stream->fragment_bitrates[index];
-  stream->fragment_bitrates[index] = new_bitrate;
-  stream->moving_bitrate += new_bitrate;
-
-  stream->moving_index += 1;
-
-  if (stream->moving_index > NUM_LOOKBACK_FRAGMENTS)
-    return stream->moving_bitrate / NUM_LOOKBACK_FRAGMENTS;
-  return stream->moving_bitrate / stream->moving_index;
-}
-
-static guint64
-gst_adaptive_demux2_stream_update_current_bitrate (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  guint64 average_bitrate;
-  guint64 fragment_bitrate;
-  guint connection_speed, min_bitrate, max_bitrate, target_download_rate;
-
-  fragment_bitrate = stream->last_bitrate;
-  GST_DEBUG_OBJECT (stream, "Download bitrate is : %" G_GUINT64_FORMAT " bps",
-      fragment_bitrate);
-
-  average_bitrate = _update_average_bitrate (demux, stream, fragment_bitrate);
-
-  GST_INFO_OBJECT (stream,
-      "last fragment bitrate was %" G_GUINT64_FORMAT, fragment_bitrate);
-  GST_INFO_OBJECT (stream,
-      "Last %u fragments average bitrate is %" G_GUINT64_FORMAT,
-      NUM_LOOKBACK_FRAGMENTS, average_bitrate);
-
-  /* Conservative approach, make sure we don't upgrade too fast */
-  GST_OBJECT_LOCK (demux);
-  stream->current_download_rate = MIN (average_bitrate, fragment_bitrate);
-
-  /* If this is the/a video stream update the overall demuxer
-   * reported bitrate and notify, to give the application a
-   * chance to choose a new connection-bitrate */
-  if ((stream->stream_type & GST_STREAM_TYPE_VIDEO) != 0) {
-    demux->current_download_rate = stream->current_download_rate;
-    GST_OBJECT_UNLOCK (demux);
-    g_object_notify (G_OBJECT (demux), "current-bandwidth");
-    GST_OBJECT_LOCK (demux);
-  }
-
-  connection_speed = demux->connection_speed;
-  min_bitrate = demux->min_bitrate;
-  max_bitrate = demux->max_bitrate;
-  GST_OBJECT_UNLOCK (demux);
-
-  if (connection_speed) {
-    GST_LOG_OBJECT (stream, "connection-speed is set to %u kbps, using it",
-        connection_speed / 1000);
-    return connection_speed;
-  }
-
-  /* No explicit connection_speed, so choose the new variant to use as a
-   * fraction of the measured download rate */
-  target_download_rate =
-      CLAMP (stream->current_download_rate, 0,
-      G_MAXUINT) * demux->bandwidth_target_ratio;
-
-  GST_DEBUG_OBJECT (stream, "Bitrate after target ratio limit (%0.2f): %u",
-      demux->bandwidth_target_ratio, target_download_rate);
-
-#if 0
-  /* Debugging code, modulate the bitrate every few fragments */
-  {
-    static guint ctr = 0;
-    if (ctr % 3 == 0) {
-      GST_INFO_OBJECT (stream, "Halving reported bitrate for debugging");
-      target_download_rate /= 2;
-    }
-    ctr++;
-  }
-#endif
-
-  if (min_bitrate > 0 && target_download_rate < min_bitrate) {
-    target_download_rate = min_bitrate;
-    GST_LOG_OBJECT (stream, "Bitrate adjusted due to min-bitrate : %u bits/s",
-        min_bitrate);
-  }
-
-  if (max_bitrate > 0 && target_download_rate > max_bitrate) {
-    target_download_rate = max_bitrate;
-    GST_LOG_OBJECT (stream, "Bitrate adjusted due to max-bitrate : %u bits/s",
-        max_bitrate);
-  }
-
-  GST_DEBUG_OBJECT (stream, "Returning target download rate of %u bps",
-      target_download_rate);
-
-  return target_download_rate;
-}
-
-/* must be called with manifest_lock taken */
-static GstFlowReturn
-gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  /* No need to advance, this isn't a real fragment */
-  if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
-    return GST_FLOW_OK;
-
-  return gst_adaptive_demux2_stream_advance_fragment (demux, stream,
-      stream->fragment.duration);
-}
-
-/* must be called with manifest_lock taken.
- * Can temporarily release manifest_lock
- */
-static GstFlowReturn
-gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer)
-{
-  return gst_adaptive_demux2_stream_push_buffer (stream, buffer);
-}
-
 static gboolean
 gst_adaptive_demux_requires_periodical_playlist_update_default (GstAdaptiveDemux
     * demux)
@@ -3877,181 +3580,6 @@ gst_adaptive_demux2_stream_seek (GstAdaptiveDemux * demux,
   return GST_FLOW_ERROR;
 }
 
-/* must be called from the scheduler */
-gboolean
-gst_adaptive_demux2_stream_has_next_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-  gboolean ret = TRUE;
-
-  if (klass->stream_has_next_fragment)
-    ret = klass->stream_has_next_fragment (stream);
-
-  return ret;
-}
-
-/* must be called from the scheduler */
-/* Called from: the ::finish_fragment() handlers when an *actual* fragment is
- * done
- *
- * @duration: Is the duration of the advancement starting from
- * stream->current_position which might not be the fragment duration after a
- * seek.
- */
-GstFlowReturn
-gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstClockTime duration)
-{
-  if (stream->last_ret != GST_FLOW_OK)
-    return stream->last_ret;
-
-  stream->last_ret =
-      gst_adaptive_demux2_stream_advance_fragment_unlocked (demux, stream,
-      duration);
-
-  return stream->last_ret;
-}
-
-/* must be called with manifest_lock taken */
-static GstFlowReturn
-gst_adaptive_demux2_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstClockTime duration)
-{
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-  GstFlowReturn ret;
-
-  g_return_val_if_fail (klass->stream_advance_fragment != NULL, GST_FLOW_ERROR);
-
-  GST_LOG_OBJECT (stream,
-      "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
-      GST_STIME_ARGS (stream->fragment.stream_time), GST_TIME_ARGS (duration));
-
-  stream->download_error_count = 0;
-  g_clear_error (&stream->last_error);
-
-#if 0
-  /* FIXME - url has no indication of byte ranges for subsegments */
-  /* FIXME: Reenable statistics sending? */
-  gst_element_post_message (GST_ELEMENT_CAST (demux),
-      gst_message_new_element (GST_OBJECT_CAST (demux),
-          gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
-              "manifest-uri", G_TYPE_STRING,
-              demux->manifest_uri, "uri", G_TYPE_STRING,
-              stream->fragment.uri, "fragment-start-time",
-              GST_TYPE_CLOCK_TIME, stream->download_start_time,
-              "fragment-stop-time", GST_TYPE_CLOCK_TIME,
-              gst_util_get_timestamp (), "fragment-size", G_TYPE_UINT64,
-              stream->download_total_bytes, "fragment-download-time",
-              GST_TYPE_CLOCK_TIME, stream->last_download_time, NULL)));
-#endif
-
-  /* Don't update to the end of the segment if in reverse playback */
-  GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
-  if (GST_CLOCK_TIME_IS_VALID (duration) && demux->segment.rate > 0) {
-    stream->parse_segment.position += duration;
-    stream->current_position += duration;
-
-    GST_DEBUG_OBJECT (stream,
-        "stream position now %" GST_TIME_FORMAT,
-        GST_TIME_ARGS (stream->current_position));
-  }
-  GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
-
-  /* When advancing with a non 1.0 rate on live streams, we need to check
-   * the live seeking range again to make sure we can still advance to
-   * that position */
-  if (demux->segment.rate != 1.0 && gst_adaptive_demux_is_live (demux)) {
-    if (!gst_adaptive_demux2_stream_in_live_seek_range (demux, stream))
-      ret = GST_FLOW_EOS;
-    else
-      ret = klass->stream_advance_fragment (stream);
-  } else if (gst_adaptive_demux_is_live (demux)
-      || gst_adaptive_demux2_stream_has_next_fragment (demux, stream)) {
-    ret = klass->stream_advance_fragment (stream);
-  } else {
-    ret = GST_FLOW_EOS;
-  }
-
-  stream->download_start_time =
-      GST_TIME_AS_USECONDS (gst_adaptive_demux2_get_monotonic_time (demux));
-
-  /* Always check if we need to switch bitrate on OK, or when live
-   * (it's normal to have EOS on advancing in live when we hit the
-   * end of the manifest) */
-  if (ret == GST_FLOW_OK || gst_adaptive_demux_is_live (demux)) {
-    GST_DEBUG_OBJECT (stream, "checking if stream requires bitrate change");
-    if (gst_adaptive_demux2_stream_select_bitrate (demux, stream,
-            gst_adaptive_demux2_stream_update_current_bitrate (demux,
-                stream))) {
-      GST_DEBUG_OBJECT (stream, "Bitrate changed. Returning FLOW_SWITCH");
-      stream->need_header = TRUE;
-      ret = (GstFlowReturn) GST_ADAPTIVE_DEMUX_FLOW_SWITCH;
-    }
-  }
-
-  return ret;
-}
-
-/* must be called with manifest_lock taken */
-static gboolean
-gst_adaptive_demux2_stream_select_bitrate (GstAdaptiveDemux *
-    demux, GstAdaptiveDemux2Stream * stream, guint64 bitrate)
-{
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-
-  if (klass->stream_select_bitrate)
-    return klass->stream_select_bitrate (stream, bitrate);
-  return FALSE;
-}
-
-/* must be called with manifest_lock taken */
-GstFlowReturn
-gst_adaptive_demux2_stream_update_fragment_info (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
-{
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-  GstFlowReturn ret;
-
-  g_return_val_if_fail (klass->stream_update_fragment_info != NULL,
-      GST_FLOW_ERROR);
-
-  /* Make sure the sub-class will update bitrate, or else
-   * we will later */
-  stream->fragment.finished = FALSE;
-
-  GST_LOG_OBJECT (stream, "position %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (stream->current_position));
-
-  ret = klass->stream_update_fragment_info (stream);
-
-  GST_LOG_OBJECT (stream, "ret:%s uri:%s",
-      gst_flow_get_name (ret), stream->fragment.uri);
-  if (ret == GST_FLOW_OK) {
-    GST_LOG_OBJECT (stream,
-        "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
-        GST_STIME_ARGS (stream->fragment.stream_time),
-        GST_TIME_ARGS (stream->fragment.duration));
-    GST_LOG_OBJECT (stream,
-        "range start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT,
-        stream->fragment.range_start, stream->fragment.range_end);
-  }
-
-  return ret;
-}
-
-/* must be called with manifest_lock taken */
-GstClockTime
-gst_adaptive_demux2_stream_get_fragment_waiting_time (GstAdaptiveDemux *
-    demux, GstAdaptiveDemux2Stream * stream)
-{
-  GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-
-  if (klass->stream_get_fragment_waiting_time)
-    return klass->stream_get_fragment_waiting_time (stream);
-  return 0;
-}
-
 static void
 handle_manifest_download_complete (DownloadRequest * request,
     DownloadRequestState state, GstAdaptiveDemux * demux)
@@ -4160,29 +3688,6 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
   return ret;
 }
 
-void
-gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f)
-{
-  g_free (f->uri);
-  f->uri = NULL;
-  f->range_start = 0;
-  f->range_end = -1;
-
-  g_free (f->header_uri);
-  f->header_uri = NULL;
-  f->header_range_start = 0;
-  f->header_range_end = -1;
-
-  g_free (f->index_uri);
-  f->index_uri = NULL;
-  f->index_range_start = 0;
-  f->index_range_end = -1;
-
-  f->stream_time = GST_CLOCK_STIME_NONE;
-  f->duration = GST_CLOCK_TIME_NONE;
-  f->finished = FALSE;
-}
-
 /* must be called with manifest_lock taken */
 gboolean
 gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux)
index 0c6470f..883b562 100644 (file)
 
 #include "gstadaptivedemuxutils.h"
 
-G_BEGIN_DECLS
-
-#define GST_TYPE_ADAPTIVE_DEMUX \
-  (gst_adaptive_demux_ng_get_type())
-#define GST_ADAPTIVE_DEMUX(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemux))
-#define GST_ADAPTIVE_DEMUX_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
-#define GST_ADAPTIVE_DEMUX_GET_CLASS(obj) \
-  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
-#define GST_IS_ADAPTIVE_DEMUX(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADAPTIVE_DEMUX))
-#define GST_IS_ADAPTIVE_DEMUX_CLASS(obj) \
-  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADAPTIVE_DEMUX))
-#define GST_ADAPTIVE_DEMUX_CAST(obj) ((GstAdaptiveDemux *)obj)
-
-#define GST_TYPE_ADAPTIVE_DEMUX2_STREAM \
-  (gst_adaptive_demux2_stream_get_type())
-#define GST_ADAPTIVE_DEMUX2_STREAM(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX2_STREAM,GstAdaptiveDemux2Stream))
-#define GST_ADAPTIVE_DEMUX2_STREAM_CAST(obj) ((GstAdaptiveDemux2Stream *)obj)
-
-typedef struct _GstAdaptiveDemux2Stream GstAdaptiveDemux2Stream;
-typedef GstObjectClass GstAdaptiveDemux2StreamClass;
+#include "gstadaptivedemux-types.h"
+#include "gstadaptivedemux-stream.h"
 
+G_BEGIN_DECLS
 
 /**
  * GST_ADAPTIVE_DEMUX_SINK_NAME:
@@ -77,8 +56,6 @@ typedef GstObjectClass GstAdaptiveDemux2StreamClass;
 
 #define GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS(obj) ((((GstAdaptiveDemux*)(obj))->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) == GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)
 
-#define GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER(obj) (((GstAdaptiveDemux2Stream *) (obj))->need_header)
-
 /**
  * GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME:
  *
@@ -101,48 +78,15 @@ typedef GstObjectClass GstAdaptiveDemux2StreamClass;
 #define GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT GST_FLOW_CUSTOM_SUCCESS_1
 
 /* Current fragment download should be aborted and restarted. The parent class
- * will call ::update_fragment_info() again to get the updated information.
+ * will call ::update_fragment_info() on the stream again to get the updated information.
  */
 #define GST_ADAPTIVE_DEMUX_FLOW_RESTART_FRAGMENT GST_FLOW_CUSTOM_SUCCESS_2
 
 /* The live stream has lost synchronization and the demuxer needs to be resetted */
 #define GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC GST_FLOW_CUSTOM_SUCCESS_2 + 1
 
-typedef enum _GstAdaptiveDemux2StreamState GstAdaptiveDemux2StreamState;
-
-typedef struct _GstAdaptiveDemux2StreamFragment GstAdaptiveDemux2StreamFragment;
-typedef struct _GstAdaptiveDemuxTrack GstAdaptiveDemuxTrack;
-typedef struct _GstAdaptiveDemuxPeriod GstAdaptiveDemuxPeriod;
-typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
-typedef struct _GstAdaptiveDemuxClass GstAdaptiveDemuxClass;
 typedef struct _GstAdaptiveDemuxPrivate GstAdaptiveDemuxPrivate;
 
-struct _GstAdaptiveDemux2StreamFragment
-{
-  /* The period-local stream time for the given fragment. */
-  GstClockTimeDiff stream_time;
-  GstClockTime duration;
-
-  gchar *uri;
-  gint64 range_start;
-  gint64 range_end;
-
-  /* when chunked downloading is used, may be be updated need_another_chunk() */
-  gint chunk_size;
-
-  /* when headers are needed */
-  gchar *header_uri;
-  gint64 header_range_start;
-  gint64 header_range_end;
-
-  /* when index is needed */
-  gchar *index_uri;
-  gint64 index_range_start;
-  gint64 index_range_end;
-
-  gboolean finished;
-};
-
 struct _GstAdaptiveDemuxTrack
 {
   gint ref_count;
@@ -249,119 +193,6 @@ struct _GstAdaptiveDemuxTrack
   gboolean output_discont;
 };
 
-enum _GstAdaptiveDemux2StreamState {
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED, /* Stream was stopped */
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART, /* Stream stopped but needs restart logic */
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_LIVE,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS,
-  GST_ADAPTIVE_DEMUX2_STREAM_STATE_ERRORED
-};
-
-struct _GstAdaptiveDemux2Stream
-{
-  GstObject object;
-
-  /* FIXME : transition to gstobject->parent */
-  GstAdaptiveDemux *demux;
-
-  /* The period to which the stream belongs, set when adding the stream to the
-   * demuxer */
-  GstAdaptiveDemuxPeriod *period;
-  
-  /* The tracks this stream targets */
-  GList *tracks;
-
-  /* The internal parsebin, forward data to track */
-  GstElement *parsebin;
-  GstPad *parsebin_sink;
-
-  gulong pad_added_id, pad_removed_id;
-  
-  GstSegment parse_segment;
-
-  /* TRUE if the current stream GstSegment should be sent downstream */
-  gboolean send_segment;
-  /* TRUE if the stream GstSegment requires recalculation (from demuxer
-     segment) */
-  gboolean compute_segment;
-  /* first_and_live applies to compute_segment */
-  gboolean first_and_live;
-
-  /* When restarting, what is the target position (in demux segment) to
-   * begin at */
-  GstClockTime start_position;
-
-  /* Track the current position (in demux segment) of the current fragment */
-  GstClockTime current_position;
-
-  GstCaps *pending_caps;
-  GstTagList *pending_tags;
-
-  GList *pending_events;
-
-  GstFlowReturn last_ret;
-  GError *last_error;
-
-  gboolean discont;
-
-  /* download tooling */
-  gboolean need_header;
-  gboolean need_index;
-
-  gboolean downloading_header;
-  gboolean downloading_index;
-
-  /* persistent, reused download request for fragment data */
-  DownloadRequest *download_request;
-
-  GstAdaptiveDemux2StreamState state;
-  guint pending_cb_id;
-  gboolean download_active;
-  /* The (global output) time at which this stream should be woken
-   * to download more input */
-  GstClockTimeDiff next_input_wakeup_time;
-
-  guint last_status_code;
-
-  gboolean pending_tracks; /* if we need to discover tracks dynamically for this stream */
-  gboolean download_finished;
-
-  gboolean starting_fragment;
-  gboolean first_fragment_buffer;
-  gint64 download_start_time;
-  gint64 download_total_bytes;
-  gint64 download_end_offset;
-  guint64 current_download_rate;
-
-  /* bitrate of the previous fragment (pre-queue2) */
-  guint64 last_bitrate;
-
-  /* Total last download time, from request to completion */
-  GstClockTime last_download_time;
-
-  /* Average for the last fragments */
-  guint64 moving_bitrate;
-  guint moving_index;
-  guint64 *fragment_bitrates;
-
-  GstAdaptiveDemux2StreamFragment fragment;
-
-  guint download_error_count;
-
-  /* Last collection provided by parsebin */
-  GstStreamCollection *stream_collection;
-
-  /* OR'd set of stream types in this stream */
-  GstStreamType stream_type;
-
-  /* The buffering threshold recommended by the subclass */
-  GstClockTime recommended_buffering_threshold;
-};
-
 /**
  * GstAdaptiveDemuxPeriod:
  *
@@ -574,116 +405,6 @@ struct _GstAdaptiveDemuxClass
                                    GstSeekFlags             flags,
                                    GstClockTimeDiff         target_ts,
                                    GstClockTimeDiff       * final_ts);
-  gboolean      (*stream_has_next_fragment)  (GstAdaptiveDemux2Stream * stream);
-  GstFlowReturn (*stream_advance_fragment) (GstAdaptiveDemux2Stream * stream);
-
-  /**
-   * stream_can_start:
-   * @demux: The #GstAdaptiveDemux
-   * @stream: a #GstAdaptiveDemux2Stream
-   *
-   * Called before starting a @stream. sub-classes can return %FALSE if more
-   * information is required before it can be started. Sub-classes will have to
-   * call gst_adaptive_demux2_stream_start() when the stream should be started.
-   */
-  gboolean      (*stream_can_start) (GstAdaptiveDemux *demux,
-                                    GstAdaptiveDemux2Stream *stream);
-
-  /**
-   * stream_update_tracks:
-   * @demux: The #GstAdaptiveDemux
-   * @stream: A #GstAdaptiveDemux2Stream
-   *
-   * Called whenever the base class collected a @collection on a @stream which has
-   * pending tracks to be created. Subclasses should override this if they
-   * create streams without tracks.
-   *
-   * * create the various tracks by analyzing the @stream stream_collection
-   * * Set the track upstream_stream_id to the corresponding stream_id from the collection
-   */
-  void          (*stream_update_tracks) (GstAdaptiveDemux *demux,
-                                        GstAdaptiveDemux2Stream *stream);
-  /**
-   * need_another_chunk:
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * If chunked downloading is used (chunk_size != 0) this is called once a
-   * chunk is finished to decide whether more has to be downloaded or not.
-   * May update chunk_size to a different value
-   */
-  gboolean      (*need_another_chunk) (GstAdaptiveDemux2Stream * stream);
-
-  /**
-   * stream_update_fragment_info:
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * Requests the stream to set the information about the current fragment to its
-   * current fragment struct
-   *
-   * Returns: #GST_FLOW_OK in success, #GST_FLOW_ERROR on error and #GST_FLOW_EOS
-   *          if there is no fragment.
-   */
-  GstFlowReturn (*stream_update_fragment_info) (GstAdaptiveDemux2Stream * stream);
-  /**
-   * stream_select_bitrate:
-   * @stream: #GstAdaptiveDemux2Stream
-   * @bitrate: the bitrate to select (in bytes per second)
-   *
-   * The stream should try to select the bitrate that is the greater, but not
-   * greater than the requested bitrate. If it needs a codec change it should
-   * create the new stream using gst_adaptive_demux2_stream_new(). If it only
-   * needs a caps change it should set the new caps using
-   * gst_adaptive_demux2_stream_set_caps().
-   *
-   * Returns: %TRUE if the stream changed bitrate, %FALSE otherwise
-   */
-  gboolean      (*stream_select_bitrate) (GstAdaptiveDemux2Stream * stream, guint64 bitrate);
-  /**
-   * stream_get_fragment_waiting_time:
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * For live streams, requests how much time should be waited before starting
-   * to download the fragment. This is useful to avoid downloading a fragment that
-   * isn't available yet.
-   *
-   * Returns: The waiting time in as a #GstClockTime
-   */
-  GstClockTime (*stream_get_fragment_waiting_time) (GstAdaptiveDemux2Stream * stream);
-
-  /**
-   * start_fragment:
-   * @demux: #GstAdaptiveDemux
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * Notifies the subclass that the given stream is starting the download
-   * of a new fragment. Can be used to reset/init internal state that is
-   * needed before each fragment, like decryption engines.
-   *
-   * Returns: %TRUE if successful.
-   */
-  gboolean      (*start_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream);
-  /**
-   * finish_fragment:
-   * @demux: #GstAdaptiveDemux
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * Notifies the subclass that a fragment download was finished.
-   * It can be used to cleanup internal state after a fragment and
-   * also push any pending data before moving to the next fragment.
-   */
-  GstFlowReturn (*finish_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream);
-  /**
-   * data_received:
-   * @demux: #GstAdaptiveDemux
-   * @stream: #GstAdaptiveDemux2Stream
-   * @buffer: #GstBuffer
-   *
-   * Notifies the subclass that a fragment chunk was downloaded. The subclass
-   * can look at the data and modify/push data as desired.
-   *
-   * Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
-   */
-  GstFlowReturn (*data_received) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
 
   /**
    * get_live_seek_range:
@@ -698,18 +419,6 @@ struct _GstAdaptiveDemuxClass
   gboolean (*get_live_seek_range) (GstAdaptiveDemux * demux, gint64 * start, gint64 * stop);
 
   /**
-   * get_presentation_offset:
-   * @demux: #GstAdaptiveDemux
-   * @stream: #GstAdaptiveDemux2Stream
-   *
-   * Gets the delay to apply to @stream.
-   *
-   * Return: a #GstClockTime representing the (positive) time offset to apply to
-   * @stream.
-   */
-  GstClockTime (*get_presentation_offset) (GstAdaptiveDemux *demux, GstAdaptiveDemux2Stream *stream);
-
-  /**
    * get_period_start_time:
    * @demux: #GstAdaptiveDemux
    *
@@ -739,8 +448,6 @@ struct _GstAdaptiveDemuxClass
 
 GType    gst_adaptive_demux_ng_get_type (void);
 
-GType    gst_adaptive_demux2_stream_get_type (void);
-
 gboolean gst_adaptive_demux2_add_stream (GstAdaptiveDemux *demux,
                                         GstAdaptiveDemux2Stream *stream);
 
@@ -757,34 +464,9 @@ GstAdaptiveDemuxTrack *gst_adaptive_demux_track_ref (GstAdaptiveDemuxTrack *trac
 void                   gst_adaptive_demux_track_unref (GstAdaptiveDemuxTrack *track);
 
 
-void gst_adaptive_demux2_stream_set_caps (GstAdaptiveDemux2Stream * stream,
-                                         GstCaps * caps);
-
-void gst_adaptive_demux2_stream_set_tags (GstAdaptiveDemux2Stream * stream,
-                                         GstTagList * tags);
-
-void gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f);
-
-GstFlowReturn gst_adaptive_demux2_stream_push_buffer (GstAdaptiveDemux2Stream * stream,
-                                                     GstBuffer * buffer);
-
-GstFlowReturn gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux * demux,
-                                                          GstAdaptiveDemux2Stream * stream,
-                                                          GstClockTime duration);
-
 gboolean gst_adaptive_demux_start_new_period (GstAdaptiveDemux * demux);
 
-void
-gst_adaptive_demux2_stream_start (GstAdaptiveDemux2Stream * stream);
-
-void gst_adaptive_demux2_stream_queue_event (GstAdaptiveDemux2Stream * stream,
-                                            GstEvent * event);
-
-gboolean gst_adaptive_demux2_stream_is_selected (GstAdaptiveDemux2Stream *stream);
-gboolean gst_adaptive_demux2_stream_is_running (GstAdaptiveDemux2Stream * stream);
-
 GstClockTime gst_adaptive_demux2_get_monotonic_time (GstAdaptiveDemux * demux);
-
 GDateTime *gst_adaptive_demux2_get_client_now_utc (GstAdaptiveDemux * demux);
 
 gboolean gst_adaptive_demux2_is_running (GstAdaptiveDemux * demux);
index 045b209..43bcfd5 100644 (file)
@@ -116,36 +116,32 @@ gst_hls_update_time_mappings (GstHLSDemux * demux,
 static void gst_hls_prune_time_mappings (GstHLSDemux * demux);
 
 static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
+
 static GstFlowReturn gst_hls_demux_stream_seek (GstAdaptiveDemux2Stream *
     stream, gboolean forward, GstSeekFlags flags, GstClockTimeDiff ts,
     GstClockTimeDiff * final_ts);
+
 static gboolean
-gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static GstFlowReturn gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
+gst_hls_demux_stream_start_fragment (GstAdaptiveDemux2Stream * stream);
+static GstFlowReturn
+gst_hls_demux_stream_finish_fragment (GstAdaptiveDemux2Stream * stream);
+static GstFlowReturn gst_hls_demux_stream_data_received (GstAdaptiveDemux2Stream
+    * stream, GstBuffer * buffer);
 
 static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream
     * stream);
-static GstFlowReturn gst_hls_demux_advance_fragment (GstAdaptiveDemux2Stream *
+static GstFlowReturn
+gst_hls_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream);
+static GstFlowReturn
+gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream);
+static gboolean gst_hls_demux_stream_can_start (GstAdaptiveDemux2Stream *
     stream);
-static GstFlowReturn gst_hls_demux_update_fragment_info (GstAdaptiveDemux2Stream
-    * stream);
-static gboolean gst_hls_demux_stream_can_start (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static void gst_hls_demux_stream_update_tracks (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream);
-static gboolean gst_hls_demux_select_bitrate (GstAdaptiveDemux2Stream * stream,
-    guint64 bitrate);
-static void gst_hls_demux_reset (GstAdaptiveDemux * demux);
-static gboolean gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux,
-    gint64 * start, gint64 * stop);
-static GstClockTime gst_hls_demux_get_presentation_offset (GstAdaptiveDemux *
-    demux, GstAdaptiveDemux2Stream * stream);
-static void gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
-    GstHLSVariantStream * variant);
+static void gst_hls_demux_stream_create_tracks (GstAdaptiveDemux2Stream *
+    stream);
+static gboolean gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream *
+    stream, guint64 bitrate);
+static GstClockTime
+gst_hls_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream);
 
 static void gst_hls_demux_stream_finalize (GObject * object);
 
@@ -161,8 +157,31 @@ static void
 gst_hls_demux_stream_class_init (GstHLSDemuxStreamClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstAdaptiveDemux2StreamClass *adaptivedemux2stream_class =
+      GST_ADAPTIVE_DEMUX2_STREAM_CLASS (klass);
 
   gobject_class->finalize = gst_hls_demux_stream_finalize;
+
+  adaptivedemux2stream_class->update_fragment_info =
+      gst_hls_demux_stream_update_fragment_info;
+  adaptivedemux2stream_class->has_next_fragment =
+      gst_hls_demux_stream_has_next_fragment;
+  adaptivedemux2stream_class->advance_fragment =
+      gst_hls_demux_stream_advance_fragment;
+  adaptivedemux2stream_class->select_bitrate =
+      gst_hls_demux_stream_select_bitrate;
+  adaptivedemux2stream_class->can_start = gst_hls_demux_stream_can_start;
+  adaptivedemux2stream_class->create_tracks =
+      gst_hls_demux_stream_create_tracks;
+
+  adaptivedemux2stream_class->start_fragment =
+      gst_hls_demux_stream_start_fragment;
+  adaptivedemux2stream_class->finish_fragment =
+      gst_hls_demux_stream_finish_fragment;
+  adaptivedemux2stream_class->data_received =
+      gst_hls_demux_stream_data_received;
+  adaptivedemux2stream_class->get_presentation_offset =
+      gst_hls_demux_stream_get_presentation_offset;
 }
 
 static void
@@ -181,6 +200,12 @@ typedef struct _GstHLSDemux2Class GstHLSDemux2Class;
 G_DEFINE_TYPE_WITH_CODE (GstHLSDemux2, gst_hls_demux2, GST_TYPE_ADAPTIVE_DEMUX,
     hls2_element_init ());
 
+static void gst_hls_demux_reset (GstAdaptiveDemux * demux);
+static gboolean gst_hls_demux_get_live_seek_range (GstAdaptiveDemux * demux,
+    gint64 * start, gint64 * stop);
+static void gst_hls_demux_set_current_variant (GstHLSDemux * hlsdemux,
+    GstHLSVariantStream * variant);
+
 static void
 gst_hls_demux_finalize (GObject * obj)
 {
@@ -263,8 +288,6 @@ gst_hls_demux2_class_init (GstHLSDemux2Class * klass)
 
   adaptivedemux_class->is_live = gst_hls_demux_is_live;
   adaptivedemux_class->get_live_seek_range = gst_hls_demux_get_live_seek_range;
-  adaptivedemux_class->get_presentation_offset =
-      gst_hls_demux_get_presentation_offset;
   adaptivedemux_class->get_duration = gst_hls_demux_get_duration;
   adaptivedemux_class->get_manifest_update_interval =
       gst_hls_demux_get_manifest_update_interval;
@@ -273,19 +296,6 @@ gst_hls_demux2_class_init (GstHLSDemux2Class * klass)
   adaptivedemux_class->reset = gst_hls_demux_reset;
   adaptivedemux_class->seek = gst_hls_demux_seek;
   adaptivedemux_class->stream_seek = gst_hls_demux_stream_seek;
-  adaptivedemux_class->stream_has_next_fragment =
-      gst_hls_demux_stream_has_next_fragment;
-  adaptivedemux_class->stream_advance_fragment = gst_hls_demux_advance_fragment;
-  adaptivedemux_class->stream_update_fragment_info =
-      gst_hls_demux_update_fragment_info;
-  adaptivedemux_class->stream_select_bitrate = gst_hls_demux_select_bitrate;
-  adaptivedemux_class->stream_can_start = gst_hls_demux_stream_can_start;
-  adaptivedemux_class->stream_update_tracks =
-      gst_hls_demux_stream_update_tracks;
-
-  adaptivedemux_class->start_fragment = gst_hls_demux_start_fragment;
-  adaptivedemux_class->finish_fragment = gst_hls_demux_finish_fragment;
-  adaptivedemux_class->data_received = gst_hls_demux_data_received;
 }
 
 static void
@@ -617,16 +627,15 @@ get_caps_of_stream_type (GstCaps * full_caps, GstStreamType streamtype)
 }
 
 static void
-gst_hls_demux_stream_update_tracks (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_create_tracks (GstAdaptiveDemux2Stream * stream)
 {
-  GstHLSDemux *hlsdemux = (GstHLSDemux *) demux;
+  GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
   GstHLSDemuxStream *hlsdemux_stream = (GstHLSDemuxStream *) stream;
   guint i;
   GstStreamType uriless_types = 0;
   GstCaps *variant_caps = NULL;
 
-  GST_DEBUG_OBJECT (demux, "Update tracks of variant stream");
+  GST_DEBUG_OBJECT (stream, "Update tracks of variant stream");
 
   if (hlsdemux->master->have_codecs) {
     variant_caps = gst_hls_master_playlist_get_common_caps (hlsdemux->master);
@@ -662,7 +671,7 @@ gst_hls_demux_stream_update_tracks (GstAdaptiveDemux * demux,
 
     if (embedded_media) {
       GstTagList *tags = gst_stream_get_tags (gst_stream);
-      GST_DEBUG_OBJECT (demux, "Adding track '%s' to main variant stream",
+      GST_DEBUG_OBJECT (stream, "Adding track '%s' to main variant stream",
           embedded_media->name);
       track =
           new_track_for_rendition (hlsdemux, embedded_media, manifest_caps,
@@ -673,10 +682,10 @@ gst_hls_demux_stream_update_tracks (GstAdaptiveDemux * demux,
           g_strdup_printf ("main-%s-%d", gst_stream_type_get_name (stream_type),
           i);
 
-      GST_DEBUG_OBJECT (demux, "Adding track '%s' to main variant stream",
+      GST_DEBUG_OBJECT (stream, "Adding track '%s' to main variant stream",
           stream_id);
       track =
-          gst_adaptive_demux_track_new (demux, stream_type,
+          gst_adaptive_demux_track_new (stream->demux, stream_type,
           flags, stream_id, manifest_caps, NULL);
       g_free (stream_id);
     }
@@ -1037,11 +1046,10 @@ out:
 }
 
 static gboolean
-gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_start_fragment (GstAdaptiveDemux2Stream * stream)
 {
   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
-  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
+  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
   const GstHLSKey *key;
   GstHLSMediaPlaylist *m3u8;
 
@@ -1069,14 +1077,14 @@ gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
 
 key_failed:
   {
-    GST_ELEMENT_ERROR (demux, STREAM, DECRYPT_NOKEY,
+    GST_ELEMENT_ERROR (hlsdemux, STREAM, DECRYPT_NOKEY,
         ("Couldn't retrieve key for decryption"), (NULL));
-    GST_WARNING_OBJECT (demux, "Failed to decrypt data");
+    GST_WARNING_OBJECT (hlsdemux, "Failed to decrypt data");
     return FALSE;
   }
 decrypt_start_failed:
   {
-    GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, ("Failed to start decrypt"),
+    GST_ELEMENT_ERROR (hlsdemux, STREAM, DECRYPT, ("Failed to start decrypt"),
         ("Couldn't set key and IV or plugin was built without crypto library"));
     return FALSE;
   }
@@ -1480,11 +1488,11 @@ out_resync:
 }
 
 static GstFlowReturn
-gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer, gboolean at_eos)
+gst_hls_demux_stream_handle_buffer (GstAdaptiveDemux2Stream * stream,
+    GstBuffer * buffer, gboolean at_eos)
 {
   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
-  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
+  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
   GstFlowReturn ret = GST_FLOW_OK;
   GstBuffer *pending_header_data = NULL;
 
@@ -1596,8 +1604,7 @@ out:
 }
 
 static GstFlowReturn
-gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_finish_fragment (GstAdaptiveDemux2Stream * stream)
 {
   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);   // FIXME: pass HlsStream into function
   GstFlowReturn ret = GST_FLOW_OK;
@@ -1626,7 +1633,7 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
       }
 
       ret =
-          gst_hls_demux_handle_buffer (demux, stream,
+          gst_hls_demux_stream_handle_buffer (stream,
           hls_stream->pending_decrypted_buffer, TRUE);
       hls_stream->pending_decrypted_buffer = NULL;
     }
@@ -1636,14 +1643,14 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
         GstBuffer *buf = hls_stream->pending_typefind_buffer;
         hls_stream->pending_typefind_buffer = NULL;
 
-        gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
+        gst_hls_demux_stream_handle_buffer (stream, buf, TRUE);
       }
 
       if (hls_stream->pending_segment_data) {
         GstBuffer *buf = hls_stream->pending_segment_data;
         hls_stream->pending_segment_data = NULL;
 
-        ret = gst_hls_demux_handle_buffer (demux, stream, buf, TRUE);
+        ret = gst_hls_demux_stream_handle_buffer (stream, buf, TRUE);
       }
     }
   }
@@ -1664,18 +1671,18 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
      * before advancing. Note that we don't have any period so we can set the
      * stream_time as-is on the stream current position */
     stream->current_position = hls_stream->current_segment->stream_time;
-    return gst_adaptive_demux2_stream_advance_fragment (demux, stream,
+    return gst_adaptive_demux2_stream_advance_fragment (stream,
         hls_stream->current_segment->duration);
   }
   return ret;
 }
 
 static GstFlowReturn
-gst_hls_demux_data_received (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream, GstBuffer * buffer)
+gst_hls_demux_stream_data_received (GstAdaptiveDemux2Stream * stream,
+    GstBuffer * buffer)
 {
   GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
-  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
+  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
 
   if (hls_stream->current_segment == NULL)
     return GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC;
@@ -1707,7 +1714,7 @@ gst_hls_demux_data_received (GstAdaptiveDemux * demux,
     decrypted_buffer =
         gst_hls_demux_decrypt_fragment (hlsdemux, hls_stream, buffer, &err);
     if (err) {
-      GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
+      GST_ELEMENT_ERROR (hlsdemux, STREAM, DECODE, ("Failed to decrypt buffer"),
           ("decryption failed %s", err->message));
       g_error_free (err);
       return GST_FLOW_ERROR;
@@ -1720,7 +1727,7 @@ gst_hls_demux_data_received (GstAdaptiveDemux * demux,
       return GST_FLOW_OK;
   }
 
-  return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
+  return gst_hls_demux_stream_handle_buffer (stream, buffer, FALSE);
 }
 
 static void
@@ -1794,7 +1801,7 @@ gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream)
 }
 
 static GstFlowReturn
-gst_hls_demux_advance_fragment (GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_advance_fragment (GstAdaptiveDemux2Stream * stream)
 {
   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
   GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
@@ -2330,7 +2337,7 @@ gst_hls_demux_stream_update_variant_playlist (GstHLSDemux * demux,
 }
 
 static GstFlowReturn
-gst_hls_demux_update_fragment_info (GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_update_fragment_info (GstAdaptiveDemux2Stream * stream)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstHLSDemuxStream *hlsdemux_stream = GST_HLS_DEMUX_STREAM_CAST (stream);
@@ -2456,14 +2463,13 @@ gst_hls_demux_update_fragment_info (GstAdaptiveDemux2Stream * stream)
 }
 
 static gboolean
-gst_hls_demux_stream_can_start (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_can_start (GstAdaptiveDemux2Stream * stream)
 {
-  GstHLSDemux *hlsdemux = (GstHLSDemux *) demux;
+  GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
   GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
   GList *tmp;
 
-  GST_DEBUG_OBJECT (demux, "is_variant:%d mappings:%p", hls_stream->is_variant,
+  GST_DEBUG_OBJECT (stream, "is_variant:%d mappings:%p", hls_stream->is_variant,
       hlsdemux->mappings);
 
   /* Variant streams can always start straight away */
@@ -2556,7 +2562,8 @@ gst_hls_demux_update_rendition_stream (GstHLSDemux * hlsdemux,
 }
 
 static gboolean
-gst_hls_demux_select_bitrate (GstAdaptiveDemux2Stream * stream, guint64 bitrate)
+gst_hls_demux_stream_select_bitrate (GstAdaptiveDemux2Stream * stream,
+    guint64 bitrate)
 {
   GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
   GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
@@ -2964,10 +2971,9 @@ gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
 }
 
 static GstClockTime
-gst_hls_demux_get_presentation_offset (GstAdaptiveDemux * demux,
-    GstAdaptiveDemux2Stream * stream)
+gst_hls_demux_stream_get_presentation_offset (GstAdaptiveDemux2Stream * stream)
 {
-  GstHLSDemux *hlsdemux = (GstHLSDemux *) demux;
+  GstHLSDemux *hlsdemux = (GstHLSDemux *) stream->demux;
   GstHLSDemuxStream *hls_stream = (GstHLSDemuxStream *) stream;
 
   GST_DEBUG_OBJECT (stream, "presentation_offset %" GST_TIME_FORMAT,