asfdemux: Change the mismatched definition
[platform/upstream/gst-plugins-ugly.git] / gst / asfdemux / gstasfdemux.c
index aa8e200..7940032 100644 (file)
@@ -14,8 +14,8 @@
  *
  * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /* TODO:
 
 #include <gst/gstutils.h>
 #include <gst/base/gstbytereader.h>
+#include <gst/base/gsttypefindhelper.h>
 #include <gst/riff/riff-media.h>
 #include <gst/tag/tag.h>
 #include <gst/gst-i18n-plugin.h>
+#include <gst/video/video.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -97,8 +99,9 @@ static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
 static void gst_asf_demux_loop (GstASFDemux * demux);
 static void
 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
-static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
-static void gst_asf_demux_pull_indices (GstASFDemux * demux);
+static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
+    GstFlowReturn * pflow);
+static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
 static gboolean
 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
@@ -121,16 +124,16 @@ gst_asf_demux_class_init (GstASFDemuxClass * klass)
 
   gstelement_class = (GstElementClass *) klass;
 
-  gst_element_class_set_details_simple (gstelement_class, "ASF Demuxer",
+  gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
       "Codec/Demuxer",
       "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
 
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&audio_src_template));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&video_src_template));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_asf_demux_sink_template));
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &audio_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &video_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_asf_demux_sink_template);
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
@@ -143,30 +146,50 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
 {
   gst_caps_replace (&stream->caps, NULL);
   if (stream->pending_tags) {
-    gst_tag_list_free (stream->pending_tags);
+    gst_tag_list_unref (stream->pending_tags);
     stream->pending_tags = NULL;
   }
+  if (stream->streamheader) {
+    gst_buffer_unref (stream->streamheader);
+    stream->streamheader = NULL;
+  }
   if (stream->pad) {
-    if (stream->active)
+    if (stream->active) {
       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
-    else
+      gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
+    } else
       gst_object_unref (stream->pad);
     stream->pad = NULL;
   }
 
-  while (stream->payloads->len > 0) {
-    AsfPayload *payload;
-    guint last;
-
-    last = stream->payloads->len - 1;
-    payload = &g_array_index (stream->payloads, AsfPayload, last);
-    gst_buffer_replace (&payload->buf, NULL);
-    g_array_remove_index (stream->payloads, last);
-  }
   if (stream->payloads) {
+    while (stream->payloads->len > 0) {
+      AsfPayload *payload;
+      guint last;
+
+      last = stream->payloads->len - 1;
+      payload = &g_array_index (stream->payloads, AsfPayload, last);
+      gst_buffer_replace (&payload->buf, NULL);
+      g_array_remove_index (stream->payloads, last);
+    }
     g_array_free (stream->payloads, TRUE);
     stream->payloads = NULL;
   }
+
+  if (stream->payloads_rev) {
+    while (stream->payloads_rev->len > 0) {
+      AsfPayload *payload;
+      guint last;
+
+      last = stream->payloads_rev->len - 1;
+      payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
+      gst_buffer_replace (&payload->buf, NULL);
+      g_array_remove_index (stream->payloads_rev, last);
+    }
+    g_array_free (stream->payloads_rev, TRUE);
+    stream->payloads_rev = NULL;
+  }
+
   if (stream->ext_props.valid) {
     g_free (stream->ext_props.payload_extensions);
     stream->ext_props.payload_extensions = NULL;
@@ -186,7 +209,7 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
     demux->adapter = NULL;
   }
   if (demux->taglist) {
-    gst_tag_list_free (demux->taglist);
+    gst_tag_list_unref (demux->taglist);
     demux->taglist = NULL;
   }
   if (demux->metadata) {
@@ -197,6 +220,10 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
     gst_structure_free (demux->global_metadata);
     demux->global_metadata = NULL;
   }
+  if (demux->mut_ex_streams) {
+    g_slist_free (demux->mut_ex_streams);
+    demux->mut_ex_streams = NULL;
+  }
 
   demux->state = GST_ASF_DEMUX_STATE_HEADER;
   g_free (demux->objpath);
@@ -234,6 +261,8 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
     /* do not remove those for not adding pads with same name */
     demux->num_audio_streams = 0;
     demux->num_video_streams = 0;
+    demux->have_group_id = FALSE;
+    demux->group_id = G_MAXUINT;
   }
   demux->num_streams = 0;
   demux->activated_streams = FALSE;
@@ -252,11 +281,15 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
 
   demux->speed_packets = 1;
 
+  demux->asf_3D_mode = GST_ASF_3D_NONE;
+
   if (chain_reset) {
     GST_LOG_OBJECT (demux, "Restarting");
     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
     demux->need_newsegment = TRUE;
+    demux->segment_seqnum = 0;
     demux->segment_running = FALSE;
+    demux->keyunit_sync = FALSE;
     demux->accurate = FALSE;
     demux->metadata = gst_caps_new_empty ();
     demux->global_metadata = gst_structure_new_empty ("metadata");
@@ -266,6 +299,9 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
   } else {
     demux->base_offset = 0;
   }
+
+  g_slist_free (demux->other_streams);
+  demux->other_streams = NULL;
 }
 
 static void
@@ -283,6 +319,10 @@ gst_asf_demux_init (GstASFDemux * demux)
       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
 
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+  demux->is_supported_format = TRUE;
+#endif
+
   /* set initial state */
   gst_asf_demux_reset (demux, FALSE);
 }
@@ -300,7 +340,8 @@ gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
     goto activate_push;
   }
 
-  pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
+  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
   gst_query_unref (query);
 
   if (!pull_mode)
@@ -337,7 +378,7 @@ gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
         demux->streaming = FALSE;
 
         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
-            demux);
+            demux, NULL);
       } else {
         res = gst_pad_stop_task (sinkpad);
       }
@@ -389,7 +430,13 @@ gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       demux->segment_ts = GST_CLOCK_TIME_NONE;
       demux->in_gap = GST_CLOCK_TIME_NONE;
       demux->need_newsegment = TRUE;
+      demux->segment_seqnum = gst_event_get_seqnum (event);
       gst_asf_demux_reset_stream_state_after_discont (demux);
+      /* if we seek back after reaching EOS, go back to packet reading state */
+      if (demux->data_offset > 0 && segment->start >= demux->data_offset
+          && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
+        demux->state = GST_ASF_DEMUX_STATE_DATA;
+      }
       GST_OBJECT_UNLOCK (demux);
 
       gst_event_unref (event);
@@ -405,10 +452,15 @@ gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
         break;
       }
       flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
+      if (!demux->activated_streams) {
+        /* If we still haven't got activated streams, the file is most likely corrupt */
+        GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
+            (_("This stream contains no data.")),
+            ("got eos and didn't receive a complete header object"));
+        break;
+      }
       if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
-        GST_ELEMENT_ERROR (demux, STREAM, FAILED,
-            (_("Internal data stream error.")),
-            ("streaming stopped, reason %s", gst_flow_get_name (flow)));
+        GST_ELEMENT_FLOW_ERROR (demux, flow);
         break;
       }
 
@@ -439,20 +491,43 @@ gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 
 static gboolean
 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
-    GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
+    GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
+    gboolean next, gboolean * eos)
 {
   GstClockTime idx_time;
   guint idx;
 
+  if (eos)
+    *eos = FALSE;
+
   if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
     return FALSE;
 
   idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
 
-  /* FIXME: seek beyond end of file should result in immediate EOS from
-   * streaming thread instead of a failed seek */
-  if (G_UNLIKELY (idx >= demux->sidx_num_entries))
+  if (next) {
+    /* if we want the next keyframe, we have to go forward till we find
+       a different packet number */
+    guint idx2;
+    if (idx >= demux->sidx_num_entries - 1) {
+      /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
+      if (eos)
+        *eos = TRUE;
+      return FALSE;
+    }
+    for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
+      if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
+        idx = idx2;
+        break;
+      }
+    }
+  }
+
+  if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
+    if (eos)
+      *eos = TRUE;
     return FALSE;
+  }
 
   *packet = demux->sidx_entries[idx].packet;
   if (speed)
@@ -490,9 +565,10 @@ gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
 
   GST_DEBUG_OBJECT (demux, "reset stream state");
 
+  gst_flow_combiner_reset (demux->flowcombiner);
   for (n = 0; n < demux->num_streams; n++) {
     demux->stream[n].discont = TRUE;
-    demux->stream[n].last_flow = GST_FLOW_OK;
+    demux->stream[n].first_buffer = TRUE;
 
     while (demux->stream[n].payloads->len > 0) {
       AsfPayload *payload;
@@ -528,6 +604,7 @@ gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
   gint64 cur, stop;
   guint packet;
   gboolean res;
+  GstEvent *byte_event;
 
   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
       &stop_type, &stop);
@@ -538,9 +615,11 @@ gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
 
   /* determine packet, by index or by estimation */
-  if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
-    packet = (guint) gst_util_uint64_scale (demux->num_packets,
-        cur, demux->play_time);
+  if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
+          NULL)) {
+    packet =
+        (guint) gst_util_uint64_scale (demux->num_packets, cur,
+        demux->play_time);
   }
 
   if (packet > demux->num_packets) {
@@ -551,14 +630,15 @@ gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
 
   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
 
-  cur = demux->data_offset + (packet * demux->packet_size);
+  cur = demux->data_offset + ((guint64) packet * demux->packet_size);
 
   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
   /* BYTE seek event */
-  event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
-      stop_type, stop);
-  res = gst_pad_push_event (demux->sinkpad, event);
+  byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
+      cur, stop_type, stop);
+  gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
+  res = gst_pad_push_event (demux->sinkpad, byte_event);
 
   return res;
 }
@@ -572,12 +652,29 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
   GstSeekType cur_type, stop_type;
   GstFormat format;
   gboolean only_need_update;
-  gboolean keyunit_sync;
+  gboolean after, before, next;
   gboolean flush;
   gdouble rate;
   gint64 cur, stop;
   gint64 seek_time;
   guint packet, speed_count = 1;
+  gboolean eos;
+  guint32 seqnum;
+  GstEvent *fevent;
+  gint i;
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+
+  if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
+    GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
+    return FALSE;
+  }
+
+  /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
+   * so first try to let it handle the seek event. */
+  if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
+    return TRUE;
 
   if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
           demux->num_packets == 0 || demux->play_time == 0)) {
@@ -590,23 +687,23 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
     return FALSE;
   }
 
-  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
-      &stop_type, &stop);
-
-  if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
-    GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
-    return FALSE;
-  }
-
   if (G_UNLIKELY (rate <= 0.0)) {
-    GST_LOG_OBJECT (demux, "backward playback is not supported yet");
-    return FALSE;
+    GST_LOG_OBJECT (demux, "backward playback");
+    demux->seek_to_cur_pos = TRUE;
+    for (i = 0; i < demux->num_streams; i++) {
+      demux->stream[i].reverse_kf_ready = FALSE;
+    }
   }
 
+  seqnum = gst_event_get_seqnum (event);
   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
   demux->accurate =
       ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
-  keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
+  demux->keyunit_sync =
+      ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
+  after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
+  before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
+  next = after && !before;
 
   if (G_UNLIKELY (demux->streaming)) {
     /* support it safely needs more segment handling, e.g. closing etc */
@@ -615,23 +712,21 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
       return FALSE;
     }
     /* we can (re)construct the start later on, but not the end */
-    if (stop_type != GST_SEEK_TYPE_NONE) {
-      GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
+    if (stop_type != GST_SEEK_TYPE_NONE &&
+        (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
+      GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
       return FALSE;
     }
-    gst_event_ref (event);
-    /* upstream might handle TIME seek, e.g. mms or rtsp,
-     * or not, e.g. http, then we give it a hand */
-    if (!gst_pad_push_event (demux->sinkpad, event))
-      return gst_asf_demux_handle_seek_push (demux, event);
-    else
-      return TRUE;
+    return gst_asf_demux_handle_seek_push (demux, event);
   }
 
   /* unlock the streaming thread */
   if (G_LIKELY (flush)) {
-    gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
-    gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
+    fevent = gst_event_new_flush_start ();
+
+    gst_event_set_seqnum (fevent, seqnum);
+    gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
+    gst_asf_demux_send_event_unlocked (demux, fevent);
   } else {
     gst_pad_pause_task (demux->sinkpad);
   }
@@ -641,44 +736,43 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
    * forever */
   GST_PAD_STREAM_LOCK (demux->sinkpad);
 
-  /* we now can stop flushing, since we have the stream lock now */
-  gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
-
-  if (G_LIKELY (flush))
-    gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop (TRUE));
+  if (G_LIKELY (flush)) {
+    /* we now can stop flushing, since we have the stream lock now */
+    fevent = gst_event_new_flush_stop (TRUE);
+    gst_event_set_seqnum (fevent, seqnum);
+    gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
+    gst_asf_demux_send_event_unlocked (demux, fevent);
+  }
 
   /* operating on copy of segment until we know the seek worked */
   segment = demux->segment;
 
-  if (G_UNLIKELY (demux->segment_running && !flush)) {
-    GstSegment newsegment;
-    GstEvent *newseg;
-
-    /* create the segment event to close the current segment */
-    gst_segment_copy_into (&segment, &newsegment);
-    newseg = gst_event_new_segment (&newsegment);
-
-    gst_asf_demux_send_event_unlocked (demux, newseg);
-  }
-
   gst_segment_do_seek (&segment, rate, format, flags, cur_type,
       cur, stop_type, stop, &only_need_update);
 
   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
 
-  seek_time = segment.start;
+  if (cur_type != GST_SEEK_TYPE_SET)
+    seek_time = segment.start;
+  else
+    seek_time = cur;
 
   /* FIXME: should check the KEY_UNIT flag; need to adjust position to
    * real start of data and segment_start to indexed time for key unit seek*/
   if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
-              &idx_time, &speed_count))) {
+              &idx_time, &speed_count, next, &eos))) {
+    gint64 offset;
+
+    if (eos) {
+      demux->packet = demux->num_packets;
+      goto skip;
+    }
+
     /* First try to query our source to see if it can convert for us. This is
        the case when our source is an mms stream, notice that in this case
        gstmms will do a time based seek to get the byte offset, this is not a
        problem as the seek to this offset needs to happen anway. */
-    gint64 offset;
-
     if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
             GST_FORMAT_BYTES, &offset)) {
       packet = (offset - demux->data_offset) / demux->packet_size;
@@ -692,7 +786,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
        * the hope of hitting a keyframe and let the sinks throw away the stuff
        * before the segment start. For audio-only this is unnecessary as every
        * frame is 'key'. */
-      if (flush && (demux->accurate || keyunit_sync)
+      if (flush && (demux->accurate || (demux->keyunit_sync && !next))
           && demux->num_video_streams > 0) {
         seek_time -= 5 * GST_SECOND;
         if (seek_time < 0)
@@ -706,7 +800,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
         packet = demux->num_packets;
     }
   } else {
-    if (G_LIKELY (keyunit_sync)) {
+    if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
@@ -720,15 +814,24 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
 
   GST_OBJECT_LOCK (demux);
   demux->segment = segment;
-  demux->packet = packet;
+  if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+    demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
+        stop, demux->play_time);
+  } else {
+    demux->packet = packet;
+  }
+
   demux->need_newsegment = TRUE;
-  demux->speed_packets = speed_count;
+  demux->segment_seqnum = seqnum;
+  demux->speed_packets =
+      GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
   gst_asf_demux_reset_stream_state_after_discont (demux);
   GST_OBJECT_UNLOCK (demux);
 
+skip:
   /* restart our task since it might have been stopped when we did the flush */
   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
-      demux);
+      demux, NULL);
 
   /* streaming can continue now */
   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
@@ -787,9 +890,10 @@ typedef struct
 } AsfObject;
 
 
-/* expect is true when the user is expeting an object,
- * when false, it will give no warnings if the object
- * is not identified
+/* Peek for an object.
+ *
+ * Returns FALSE is the object is corrupted (such as the reported
+ * object size being greater than 2**32bits.
  */
 static gboolean
 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
@@ -797,6 +901,9 @@ asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
 {
   ASFGuid guid;
 
+  /* Callers should have made sure that data_len is big enough */
+  g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
+
   if (data_len < ASF_OBJECT_HEADER_SIZE)
     return FALSE;
 
@@ -805,8 +912,6 @@ asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
   guid.v3 = GST_READ_UINT32_LE (data + 8);
   guid.v4 = GST_READ_UINT32_LE (data + 12);
 
-  object->size = GST_READ_UINT64_LE (data + 16);
-
   /* FIXME: make asf_demux_identify_object_guid() */
   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
   if (object->id == ASF_OBJ_UNDEFINED && expect) {
@@ -814,6 +919,14 @@ asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
         guid.v1, guid.v2, guid.v3, guid.v4);
   }
 
+  object->size = GST_READ_UINT64_LE (data + 16);
+  if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
+    GST_WARNING_OBJECT (demux,
+        "ASF Object size corrupted (greater than 32bit)");
+    return FALSE;
+  }
+
+
   return TRUE;
 }
 
@@ -836,17 +949,18 @@ gst_asf_demux_release_old_pads (GstASFDemux * demux)
 static GstFlowReturn
 gst_asf_demux_chain_headers (GstASFDemux * demux)
 {
-  GstFlowReturn flow;
   AsfObject obj;
   guint8 *header_data, *data = NULL;
   const guint8 *cdata = NULL;
   guint64 header_size;
+  GstFlowReturn flow = GST_FLOW_OK;
 
   cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
   if (cdata == NULL)
     goto need_more_data;
 
-  asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+  if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
+    goto parse_failed;
   if (obj.id != ASF_OBJ_HEADER)
     goto wrong_type;
 
@@ -903,36 +1017,6 @@ parse_failed:
   }
 }
 
-static GstFlowReturn
-gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
-    GstFlowReturn flow)
-{
-  int i;
-
-  GST_DEBUG_OBJECT (demux, "Aggregating");
-
-  /* Store the value */
-  stream->last_flow = flow;
-
-  /* any other error that is not not-linked can be returned right away */
-  if (flow != GST_FLOW_NOT_LINKED)
-    goto done;
-
-  for (i = 0; i < demux->num_streams; i++) {
-    if (demux->stream[i].active) {
-      flow = demux->stream[i].last_flow;
-      GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
-          gst_flow_get_name (flow));
-      if (flow != GST_FLOW_NOT_LINKED)
-        goto done;
-    }
-  }
-
-  /* If we got here, then all our active streams are not linked */
-done:
-  return flow;
-}
-
 static gboolean
 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
     GstBuffer ** p_buf, GstFlowReturn * p_flow)
@@ -971,29 +1055,39 @@ gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
   return TRUE;
 }
 
-static void
+static GstFlowReturn
 gst_asf_demux_pull_indices (GstASFDemux * demux)
 {
   GstBuffer *buf = NULL;
   guint64 offset;
   guint num_read = 0;
+  GstFlowReturn ret = GST_FLOW_OK;
 
   offset = demux->index_offset;
 
   if (G_UNLIKELY (offset == 0)) {
     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
-    return;
+    /* non-fatal */
+    return GST_FLOW_OK;
   }
 
   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
-    GstFlowReturn flow;
     AsfObject obj;
     GstMapInfo map;
     guint8 *bufdata;
+    guint64 obj_size;
 
     gst_buffer_map (buf, &map, GST_MAP_READ);
     g_assert (map.size >= 16 + 8);
-    asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+    if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
+      GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
+      GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
+              64));
+      gst_buffer_unmap (buf, &map);
+      gst_buffer_replace (&buf, NULL);
+      /* Non-fatal, return */
+      break;
+    }
     gst_buffer_unmap (buf, &map);
     gst_buffer_replace (&buf, NULL);
 
@@ -1015,16 +1109,27 @@ gst_asf_demux_pull_indices (GstASFDemux * demux)
     gst_buffer_map (buf, &map, GST_MAP_READ);
     g_assert (map.size >= obj.size);
     bufdata = (guint8 *) map.data;
-    flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
+    obj_size = obj.size;
+    ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
     gst_buffer_unmap (buf, &map);
     gst_buffer_replace (&buf, NULL);
 
-    if (G_UNLIKELY (flow != GST_FLOW_OK))
+    if (ret == ASF_FLOW_NEED_MORE_DATA) {
+      /* Since indices are at the end of the file, if we need more data,
+       * we consider it as a non-fatal corrupted index */
+      ret = GST_FLOW_OK;
+      break;
+    }
+
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
       break;
 
     ++num_read;
   }
-  GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
+
+  GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
+      gst_flow_get_name (ret));
+  return ret;
 }
 
 static gboolean
@@ -1032,7 +1137,10 @@ gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
 {
   AsfObject obj;
 
-  asf_demux_peek_object (demux, data, 50, &obj, TRUE);
+  if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
+    GST_WARNING_OBJECT (demux, "Corrupted data");
+    return FALSE;
+  }
   if (obj.id != ASF_OBJ_DATA) {
     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
     return FALSE;
@@ -1074,14 +1182,19 @@ gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
       demux->data_offset, demux->data_size, demux->index_offset);
-
+#ifdef TIZEN_FEATURE_ASFDEMUX_CHECK_DATA_SIZE
+  if (demux->data_size == 0) {
+    GST_WARNING_OBJECT (demux, "DATA object size is zero");
+    return FALSE;
+  }
+#endif
   return TRUE;
 }
 
 static gboolean
-gst_asf_demux_pull_headers (GstASFDemux * demux)
+gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
 {
-  GstFlowReturn flow;
+  GstFlowReturn flow = GST_FLOW_OK;
   AsfObject obj;
   GstBuffer *buf = NULL;
   guint64 size;
@@ -1091,23 +1204,28 @@ gst_asf_demux_pull_headers (GstASFDemux * demux)
   GST_LOG_OBJECT (demux, "reading headers");
 
   /* pull HEADER object header, so we know its size */
-  if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
+  if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
     goto read_failed;
 
   gst_buffer_map (buf, &map, GST_MAP_READ);
   g_assert (map.size >= 16 + 8);
-  asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+  if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
+    gst_buffer_unmap (buf, &map);
+    gst_buffer_replace (&buf, NULL);
+    flow = GST_FLOW_ERROR;
+    goto read_failed;
+  }
   gst_buffer_unmap (buf, &map);
   gst_buffer_replace (&buf, NULL);
 
   if (obj.id != ASF_OBJ_HEADER)
     goto wrong_type;
 
-  GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
+  GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
 
   /* pull HEADER object */
   if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
-          NULL))
+          &flow))
     goto read_failed;
 
   size = obj.size;              /* don't want obj.size changed */
@@ -1128,7 +1246,7 @@ gst_asf_demux_pull_headers (GstASFDemux * demux)
 
   /* now pull beginning of DATA object before packet data */
   if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
-          NULL))
+          &flow))
     goto read_failed;
 
   gst_buffer_map (buf, &map, GST_MAP_READ);
@@ -1154,17 +1272,24 @@ wrong_type:
     }
     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
         ("This doesn't seem to be an ASF file"));
+    *pflow = GST_FLOW_ERROR;
     return FALSE;
   }
 
 no_streams:
+  flow = GST_FLOW_ERROR;
+  GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+      ("header parsing failed, or no streams found, flow = %s",
+          gst_flow_get_name (flow)));
 read_failed:
 parse_failed:
   {
     if (buf)
       gst_buffer_unmap (buf, &map);
     gst_buffer_replace (&buf, NULL);
-    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
+    if (flow == ASF_FLOW_NEED_MORE_DATA)
+      flow = GST_FLOW_ERROR;
+    *pflow = flow;
     return FALSE;
   }
 }
@@ -1174,6 +1299,7 @@ all_streams_prerolled (GstASFDemux * demux)
 {
   GstClockTime preroll_time;
   guint i, num_no_data = 0;
+  AsfStreamType prerolled_types = 0, all_types = 0;
 
   /* Allow at least 500ms of preroll_time  */
   preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
@@ -1182,30 +1308,47 @@ all_streams_prerolled (GstASFDemux * demux)
    * and (b) the timestamp of last piece of data queued is < demux->preroll
    * AND there is at least one other stream with data queued */
   for (i = 0; i < demux->num_streams; ++i) {
-    AsfPayload *last_payload;
+    AsfPayload *last_payload = NULL;
     AsfStream *stream;
-    guint last_idx;
+    gint last_idx;
 
     stream = &demux->stream[i];
+
+    all_types |= stream->type;
+
     if (G_UNLIKELY (stream->payloads->len == 0)) {
       ++num_no_data;
       GST_LOG_OBJECT (stream->pad, "no data queued");
       continue;
     }
 
-    last_idx = stream->payloads->len - 1;
-    last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+    prerolled_types |= stream->type;
+
+    /* find last payload with timestamp */
+    for (last_idx = stream->payloads->len - 1;
+        last_idx >= 0 && (last_payload == NULL
+            || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
+      last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+    }
 
     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
         GST_TIME_ARGS (preroll_time));
-    if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
+    if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
+            || last_payload->ts <= preroll_time)) {
       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
       return FALSE;
     }
   }
 
-  if (G_UNLIKELY (num_no_data == demux->num_streams))
+  GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
+      all_types, prerolled_types);
+
+  /* If streams of each present type have prerolled, we are good to go */
+  if (all_types != 0 && prerolled_types == all_types)
+    return TRUE;
+
+  if (G_UNLIKELY (num_no_data > 0))
     return FALSE;
 
   return TRUE;
@@ -1250,10 +1393,162 @@ gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
 }
 #endif
 
+static void
+gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
+{
+  /* remember the first queued timestamp for the segment */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
+          GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
+    GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (demux->first_ts));
+    demux->segment_ts = payload_ts;
+    /* always note, but only determines segment when streaming */
+    if (demux->streaming)
+      gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
+          GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
+          GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
+  }
+}
+
+static gboolean
+gst_asf_demux_get_first_ts (GstASFDemux * demux)
+{
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
+    GstClockTime first_ts = GST_CLOCK_TIME_NONE;
+    int i;
+
+    /* go trhough each stream, find smallest timestamp */
+    for (i = 0; i < demux->num_streams; ++i) {
+      AsfStream *stream;
+      int j;
+      GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
+      GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE;        /* second smallest timestamp */
+      stream = &demux->stream[i];
+
+      for (j = 0; j < stream->payloads->len; ++j) {
+        AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
+        if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+            (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
+                || stream_min_ts > payload->ts)) {
+          stream_min_ts = payload->ts;
+        }
+        if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+            payload->ts > stream_min_ts &&
+            (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
+                || stream_min_ts2 > payload->ts)) {
+          stream_min_ts2 = payload->ts;
+        }
+      }
+
+      /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
+         regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
+         which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
+         from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
+         and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
+
+      GST_DEBUG_OBJECT (demux,
+          "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
+          GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
+          GST_TIME_ARGS (stream_min_ts2));
+
+      if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND)    /* first timestamp is 0 and second is significantly larger, disregard the 0 */
+        stream_min_ts = stream_min_ts2;
+
+      if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
+          (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
+        first_ts = stream_min_ts;
+    }
+
+    if (!GST_CLOCK_TIME_IS_VALID (first_ts))    /* can happen */
+      first_ts = 0;
+
+    demux->first_ts = first_ts;
+
+    /* update packets queued before we knew first timestamp */
+    for (i = 0; i < demux->num_streams; ++i) {
+      AsfStream *stream;
+      int j;
+      stream = &demux->stream[i];
+
+      for (j = 0; j < stream->payloads->len; ++j) {
+        AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
+        if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
+          if (payload->ts > first_ts)
+            payload->ts -= first_ts;
+          else
+            payload->ts = 0;
+        }
+      }
+    }
+  }
+
+  gst_asf_demux_check_segment_ts (demux, 0);
+
+  return TRUE;
+}
+
+static gboolean
+gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
+{
+  /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
+     and often set wrong, inspecting the data is the only way that seem to be working */
+  GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
+  GstCaps *caps = NULL;
+  int i;
+  GstAdapter *adapter = gst_adapter_new ();
+
+  for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
+    const guint8 *data;
+    AsfPayload *payload;
+    int len;
+
+    payload = &g_array_index (stream->payloads, AsfPayload, i);
+    gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
+    len = gst_adapter_available (adapter);
+    data = gst_adapter_map (adapter, len);
+
+  again:
+
+#define MIN_LENGTH 128
+
+    /* look for the sync points */
+    while (TRUE) {
+      if (len < MIN_LENGTH ||   /* give typefind something to work on */
+          (data[0] == 0x0b && data[1] == 0x77) ||       /* AC-3 sync point */
+          (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF))  /* MPEG sync point */
+        break;
+      ++data;
+      --len;
+    }
+
+    gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
+            data, len, &prob));
+
+    if (prob < GST_TYPE_FIND_LIKELY) {
+      ++data;
+      --len;
+      if (len > MIN_LENGTH)
+        /* this wasn't it, look for another sync point */
+        goto again;
+    }
+
+    gst_adapter_unmap (adapter);
+  }
+
+  gst_object_unref (adapter);
+
+  if (caps) {
+    gst_caps_take (&stream->caps, caps);
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
 static gboolean
 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
 {
-  guint i;
+  guint i, actual_streams = 0;
 
   if (demux->activated_streams)
     return TRUE;
@@ -1263,19 +1558,37 @@ gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
     return FALSE;
   }
 
+  if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
+    return FALSE;
+
   for (i = 0; i < demux->num_streams; ++i) {
     AsfStream *stream = &demux->stream[i];
 
     if (stream->payloads->len > 0) {
+
+      if (stream->inspect_payload &&    /* dvr-ms required payload inspection */
+          !stream->active &&    /* do not inspect active streams (caps were already set) */
+          !gst_asf_demux_update_caps_from_payload (demux, stream) &&    /* failed to determine caps */
+          stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
+        /* try to gather some more data  */
+        return FALSE;
+      }
       /* we don't check mutual exclusion stuff here; either we have data for
        * a stream, then we active it, or we don't, then we'll ignore it */
       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
       gst_asf_demux_activate_stream (demux, stream);
+      actual_streams += 1;
     } else {
       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
     }
   }
 
+  if (actual_streams == 0) {
+    /* We don't have any streams activated ! */
+    GST_ERROR_OBJECT (demux, "No streams activated!");
+    return FALSE;
+  }
+
   gst_asf_demux_release_old_pads (demux);
 
   demux->activated_streams = TRUE;
@@ -1297,6 +1610,7 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
 
   for (i = 0; i < demux->num_streams; ++i) {
     AsfStream *stream;
+    int j;
 
     stream = &demux->stream[i];
 
@@ -1305,33 +1619,80 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
      * don't need to be decoded after a seek, sending only data from the
      * keyframe directly before our segment start */
     if (stream->payloads->len > 0) {
-      AsfPayload *payload;
-      guint last_idx;
-
-      last_idx = stream->payloads->len - 1;
-      payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
-      if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
-              (payload->ts < demux->segment.start))) {
-        if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
-          GST_DEBUG_OBJECT (stream->pad,
-              "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
-              GST_TIME_ARGS (payload->ts));
-          demux->segment.start = payload->ts;
-          demux->segment.time = payload->ts;
+      AsfPayload *payload = NULL;
+      gint last_idx;
+
+      if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+        /* Reverse playback */
+
+        if (stream->is_video) {
+          /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
+          if (stream->reverse_kf_ready) {
+            payload =
+                &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
+            if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
+              /* TODO : remove payload from the list? */
+              continue;
+            }
+          } else {
+            continue;
+          }
         } else {
-          GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
-              GST_TIME_FORMAT " which is before our segment start %"
-              GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
-              GST_TIME_ARGS (demux->segment.start));
-          continue;
+          /* find first complete payload with timestamp */
+          for (j = stream->payloads->len - 1;
+              j >= 0 && (payload == NULL
+                  || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
+            payload = &g_array_index (stream->payloads, AsfPayload, j);
+          }
+
+          /* If there's a complete payload queued for this stream */
+          if (!gst_asf_payload_is_complete (payload))
+            continue;
+
         }
-      }
+      } else {
 
-      /* Now see if there's a complete payload queued for this stream */
+        /* find last payload with timestamp */
+        for (last_idx = stream->payloads->len - 1;
+            last_idx >= 0 && (payload == NULL
+                || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
+          payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+        }
 
-      payload = &g_array_index (stream->payloads, AsfPayload, 0);
-      if (!gst_asf_payload_is_complete (payload))
-        continue;
+        /* if this is first payload after seek we might need to update the segment */
+        if (GST_CLOCK_TIME_IS_VALID (payload->ts))
+          gst_asf_demux_check_segment_ts (demux, payload->ts);
+
+        if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+                (payload->ts < demux->segment.start))) {
+          if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
+                  && payload->keyframe)) {
+            GST_DEBUG_OBJECT (stream->pad,
+                "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (payload->ts));
+            demux->segment.start = payload->ts;
+            demux->segment.time = payload->ts;
+          } else {
+            GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
+                GST_TIME_FORMAT " which is before our segment start %"
+                GST_TIME_FORMAT ", not pushing yet",
+                GST_TIME_ARGS (payload->ts),
+                GST_TIME_ARGS (demux->segment.start));
+            continue;
+          }
+        }
+        payload = NULL;
+        /* find first complete payload with timestamp */
+        for (j = 0;
+            j < stream->payloads->len && (payload == NULL
+                || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
+          payload = &g_array_index (stream->payloads, AsfPayload, j);
+        }
+
+        /* Now see if there's a complete payload queued for this stream */
+        if (!gst_asf_payload_is_complete (payload))
+          continue;
+      }
 
       /* ... and whether its timestamp is lower than the current best */
       if (best_stream == NULL || best_payload->ts > payload->ts) {
@@ -1356,18 +1717,26 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
     /* streams are now activated */
   }
 
-  /* wait until we had a chance to "lock on" some payload's timestamp */
-  if (G_UNLIKELY (demux->need_newsegment
-          && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
-    return GST_FLOW_OK;
-
   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
     AsfPayload *payload;
+    GstClockTime timestamp = GST_CLOCK_TIME_NONE;
+    GstClockTime duration = GST_CLOCK_TIME_NONE;
 
-    payload = &g_array_index (stream->payloads, AsfPayload, 0);
+    /* wait until we had a chance to "lock on" some payload's timestamp */
+    if (G_UNLIKELY (demux->need_newsegment
+            && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
+      return GST_FLOW_OK;
+
+    if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
+        && stream->payloads->len) {
+      payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
+    } else {
+      payload = &g_array_index (stream->payloads, AsfPayload, 0);
+    }
 
     /* do we need to send a newsegment event */
     if ((G_UNLIKELY (demux->need_newsegment))) {
+      GstEvent *segment_event;
 
       /* safe default if insufficient upstream info */
       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
@@ -1380,8 +1749,9 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
       }
 
       /* FIXME : only if ACCURATE ! */
-      if (G_LIKELY (!demux->accurate
-              && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
+      if (G_LIKELY (demux->keyunit_sync && !demux->accurate
+              && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
+          && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
         GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
             GST_TIME_ARGS (payload->ts));
         demux->segment.start = payload->ts;
@@ -1392,12 +1762,16 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
           &demux->segment);
 
       /* note: we fix up all timestamps to start from 0, so this should be ok */
-      gst_asf_demux_send_event_unlocked (demux,
-          gst_event_new_segment (&demux->segment));
+      segment_event = gst_event_new_segment (&demux->segment);
+      if (demux->segment_seqnum)
+        gst_event_set_seqnum (segment_event, demux->segment_seqnum);
+      gst_asf_demux_send_event_unlocked (demux, segment_event);
 
       /* now post any global tags we may have found */
-      if (demux->taglist == NULL)
+      if (demux->taglist == NULL) {
         demux->taglist = gst_tag_list_new_empty ();
+        gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
+      }
 
       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
           GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
@@ -1408,6 +1782,7 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
       demux->taglist = NULL;
 
       demux->need_newsegment = FALSE;
+      demux->segment_seqnum = 0;
       demux->segment_running = TRUE;
     }
 
@@ -1422,7 +1797,7 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
     /* We have the whole packet now so we should push the packet to
      * the src pad now. First though we should check if we need to do
      * descrambling */
-    if (G_UNLIKELY (demux->span > 1)) {
+    if (G_UNLIKELY (stream->span > 1)) {
       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
     }
 
@@ -1456,8 +1831,8 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
           payload->interlaced);
       stream->interlaced = payload->interlaced;
       stream->caps = gst_caps_make_writable (stream->caps);
-      gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
-          stream->interlaced, NULL);
+      gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
+          (stream->interlaced ? "mixed" : "progressive"), NULL);
       gst_pad_set_caps (stream->pad, stream->caps);
     }
 
@@ -1465,26 +1840,93 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
      * typically useful for live src, but might (unavoidably) mess with
      * position reporting if a live src is playing not so live content
      * (e.g. rtspsrc taking some time to fall back to tcp) */
-    GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
+    timestamp = payload->ts;
+    if (GST_CLOCK_TIME_IS_VALID (timestamp)
+        && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+      timestamp += demux->in_gap;
+
+      /* Check if we're after the segment already, if so no need to push
+       * anything here */
+      if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
+        GST_DEBUG_OBJECT (stream->pad,
+            "Payload after segment stop %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (demux->segment.stop));
+        ret =
+            gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+            GST_FLOW_EOS);
+        gst_buffer_unref (payload->buf);
+        payload->buf = NULL;
+        g_array_remove_index (stream->payloads, 0);
+        /* Break out as soon as we have an issue */
+        if (G_UNLIKELY (ret != GST_FLOW_OK))
+          break;
+
+        continue;
+      }
+    }
+
+    GST_BUFFER_PTS (payload->buf) = timestamp;
+
     if (payload->duration == GST_CLOCK_TIME_NONE
-        && stream->ext_props.avg_time_per_frame != 0)
-      GST_BUFFER_DURATION (payload->buf) =
-          stream->ext_props.avg_time_per_frame * 100;
-    else
-      GST_BUFFER_DURATION (payload->buf) = payload->duration;
+        && stream->ext_props.avg_time_per_frame != 0) {
+      duration = stream->ext_props.avg_time_per_frame * 100;
+    } else {
+      duration = payload->duration;
+    }
+    GST_BUFFER_DURATION (payload->buf) = duration;
 
     /* FIXME: we should really set durations on buffers if we can */
 
-    GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
-        ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
-        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
-        GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
-        gst_buffer_get_size (payload->buf));
+    GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
+        payload->buf);
+
+    if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
+      if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
+        GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+      }
+    } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+      GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+    }
+
+
+    if (stream->active) {
+      if (G_UNLIKELY (stream->first_buffer)) {
+        if (stream->streamheader != NULL) {
+          GST_DEBUG_OBJECT (stream->pad,
+              "Pushing streamheader before first buffer");
+          gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
+        }
+        stream->first_buffer = FALSE;
+      }
+
+      if (GST_CLOCK_TIME_IS_VALID (timestamp)
+          && timestamp > demux->segment.position) {
+        demux->segment.position = timestamp;
+        if (GST_CLOCK_TIME_IS_VALID (duration))
+          demux->segment.position += timestamp;
+      }
 
-    ret = gst_pad_push (stream->pad, payload->buf);
-    ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
+      ret = gst_pad_push (stream->pad, payload->buf);
+      ret =
+          gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+          ret);
+    } else {
+      gst_buffer_unref (payload->buf);
+      ret = GST_FLOW_OK;
+    }
     payload->buf = NULL;
-    g_array_remove_index (stream->payloads, 0);
+    if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
+        && stream->reverse_kf_ready) {
+      g_array_remove_index (stream->payloads, stream->kf_pos);
+      stream->kf_pos--;
+
+      if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
+        stream->kf_pos = 0;
+        stream->reverse_kf_ready = FALSE;
+      }
+    } else {
+      g_array_remove_index (stream->payloads, 0);
+    }
 
     /* Break out as soon as we have an issue */
     if (G_UNLIKELY (ret != GST_FLOW_OK))
@@ -1499,6 +1941,7 @@ gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
 {
   AsfObject obj;
   GstMapInfo map;
+  gboolean valid;
   g_assert (buf != NULL);
 
   GST_LOG_OBJECT (demux, "Checking if buffer is a header");
@@ -1512,9 +1955,11 @@ gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
   }
 
   /* check if it is a header */
-  asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+  valid =
+      asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
+      TRUE);
   gst_buffer_unmap (buf, &map);
-  if (obj.id == ASF_OBJ_HEADER) {
+  if (valid && obj.id == ASF_OBJ_HEADER) {
     return TRUE;
   }
   return FALSE;
@@ -1551,15 +1996,15 @@ gst_asf_demux_loop (GstASFDemux * demux)
   GstFlowReturn flow = GST_FLOW_OK;
   GstBuffer *buf = NULL;
   guint64 off;
-  gboolean sent_eos = FALSE;
 
   if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
-    if (!gst_asf_demux_pull_headers (demux)) {
-      flow = GST_FLOW_ERROR;
+    if (!gst_asf_demux_pull_headers (demux, &flow)) {
       goto pause;
     }
 
-    gst_asf_demux_pull_indices (demux);
+    flow = gst_asf_demux_pull_indices (demux);
+    if (flow != GST_FLOW_OK)
+      goto pause;
   }
 
   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
@@ -1576,19 +2021,20 @@ gst_asf_demux_loop (GstASFDemux * demux)
   if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
               demux->packet_size * demux->speed_packets, &buf, &flow))) {
     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
-    if (flow == GST_FLOW_EOS)
+    if (flow == GST_FLOW_EOS) {
       goto eos;
-    else if (flow == GST_FLOW_FLUSHING) {
+    else if (flow == GST_FLOW_FLUSHING) {
       GST_DEBUG_OBJECT (demux, "Not fatal");
       goto pause;
-    } else
+    } else {
       goto read_failed;
+    }
   }
 
   if (G_LIKELY (demux->speed_packets == 1)) {
-    /* FIXME: maybe we should just skip broken packets and error out only
-     * after a few broken packets in a row? */
-    if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
+    GstAsfDemuxParsePacketError err;
+    err = gst_asf_demux_parse_packet (demux, buf);
+    if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
       /* when we don't know when the data object ends, we should check
        * for a chained asf */
       if (demux->num_packets == 0) {
@@ -1600,24 +2046,48 @@ gst_asf_demux_loop (GstASFDemux * demux)
           return;
         }
       }
-      goto parse_error;
+      /* FIXME: We should tally up fatal errors and error out only
+       * after a few broken packets in a row? */
+
+      GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
+      gst_buffer_unref (buf);
+
+      if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
+          && !demux->seek_to_cur_pos) {
+        --demux->packet;
+        if (demux->packet < 0) {
+          goto eos;
+        }
+      } else {
+        ++demux->packet;
+      }
+
+      return;
     }
 
     flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
 
-    ++demux->packet;
+    if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
+        && !demux->seek_to_cur_pos) {
+      --demux->packet;
+      if (demux->packet < 0) {
+        goto eos;
+      }
+    } else {
+      ++demux->packet;
+    }
 
   } else {
     guint n;
     for (n = 0; n < demux->speed_packets; n++) {
       GstBuffer *sub;
+      GstAsfDemuxParsePacketError err;
 
       sub =
-          gst_buffer_copy_region (buf, GST_BUFFER_COPY_NONE,
+          gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
           n * demux->packet_size, demux->packet_size);
-      /* FIXME: maybe we should just skip broken packets and error out only
-       * after a few broken packets in a row? */
-      if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
+      err = gst_asf_demux_parse_packet (demux, sub);
+      if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
         /* when we don't know when the data object ends, we should check
          * for a chained asf */
         if (demux->num_packets == 0) {
@@ -1630,12 +2100,17 @@ gst_asf_demux_loop (GstASFDemux * demux)
             return;
           }
         }
-        goto parse_error;
+        /* FIXME: We should tally up fatal errors and error out only
+         * after a few broken packets in a row? */
+
+        GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
+        flow = GST_FLOW_OK;
       }
 
       gst_buffer_unref (sub);
 
-      flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
+      if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
+        flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
 
       ++demux->packet;
 
@@ -1647,8 +2122,9 @@ gst_asf_demux_loop (GstASFDemux * demux)
 
   gst_buffer_unref (buf);
 
-  if (G_UNLIKELY (demux->num_packets > 0
-          && demux->packet >= demux->num_packets)) {
+  if (G_UNLIKELY ((demux->num_packets > 0
+              && demux->packet >= demux->num_packets)
+          || flow == GST_FLOW_EOS)) {
     GST_LOG_OBJECT (demux, "reached EOS");
     goto eos;
   }
@@ -1669,7 +2145,7 @@ eos:
      * less data queued than required for preroll; force stream activation and
      * send any pending payloads before sending EOS */
     if (!demux->activated_streams)
-      gst_asf_demux_push_complete_payloads (demux, TRUE);
+      flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
 
     /* we want to push an eos or post a segment-done in any case */
     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
@@ -1684,6 +2160,8 @@ eos:
       gst_element_post_message (GST_ELEMENT_CAST (demux),
           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
               stop));
+      gst_asf_demux_send_event_unlocked (demux,
+          gst_event_new_segment_done (GST_FORMAT_TIME, stop));
     } else if (flow != GST_FLOW_EOS) {
       /* check if we have a chained asf, in case, we don't eos yet */
       if (gst_asf_demux_check_chained_asf (demux)) {
@@ -1692,10 +2170,17 @@ eos:
         return;
       }
     }
-    /* normal playback, send EOS to all linked pads */
-    GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
-    gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
-    sent_eos = TRUE;
+
+    if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
+      if (demux->activated_streams) {
+        /* normal playback, send EOS to all linked pads */
+        GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
+        gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+      } else {
+        GST_WARNING_OBJECT (demux, "EOS without exposed streams");
+        flow = GST_FLOW_EOS;
+      }
+    }
     /* ... and fall through to pause */
   }
 pause:
@@ -1705,17 +2190,16 @@ pause:
     demux->segment_running = FALSE;
     gst_pad_pause_task (demux->sinkpad);
 
-    /* For the error cases (not EOS) */
-    if (!sent_eos) {
-      if (flow == GST_FLOW_EOS)
-        gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
-      else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
-        /* Post an error. Hopefully something else already has, but if not... */
-        GST_ELEMENT_ERROR (demux, STREAM, FAILED,
-            (_("Internal data stream error.")),
-            ("streaming stopped, reason %s", gst_flow_get_name (flow)));
-      }
+    /* For the error cases */
+    if (flow == GST_FLOW_EOS && !demux->activated_streams) {
+      GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+          ("This doesn't seem to be an ASF file"));
+    } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
+      /* Post an error. Hopefully something else already has, but if not... */
+      GST_ELEMENT_FLOW_ERROR (demux, flow);
+      gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
     }
+
     return;
   }
 
@@ -1723,10 +2207,11 @@ pause:
 read_failed:
   {
     GST_DEBUG_OBJECT (demux, "Read failed, doh");
-    gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
     flow = GST_FLOW_EOS;
     goto pause;
   }
+#if 0
+  /* See FIXMEs above */
 parse_error:
   {
     gst_buffer_unref (buf);
@@ -1736,6 +2221,7 @@ parse_error:
     flow = GST_FLOW_ERROR;
     goto pause;
   }
+#endif
 }
 
 #define GST_ASF_DEMUX_CHECK_HEADER_YES       0
@@ -1751,12 +2237,12 @@ gst_asf_demux_check_header (GstASFDemux * demux)
   if (cdata == NULL)            /* need more data */
     return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
 
-  asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
-  if (obj.id != ASF_OBJ_HEADER) {
-    return GST_ASF_DEMUX_CHECK_HEADER_NO;
-  } else {
+  if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
+      && obj.id == ASF_OBJ_HEADER) {
     return GST_ASF_DEMUX_CHECK_HEADER_YES;
   }
+
+  return GST_ASF_DEMUX_CHECK_HEADER_NO;
 }
 
 static GstFlowReturn
@@ -1820,6 +2306,7 @@ gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
       while (gst_adapter_available (demux->adapter) >= data_size) {
         GstBuffer *buf;
+        GstAsfDemuxParsePacketError err;
 
         /* we don't know the length of the stream
          * check for a chained asf everytime */
@@ -1840,15 +2327,16 @@ gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
         buf = gst_adapter_take_buffer (demux->adapter, data_size);
 
-        /* FIXME: maybe we should just skip broken packets and error out only
+        /* FIXME: We should tally up fatal errors and error out only
          * after a few broken packets in a row? */
-        if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
-          GST_WARNING_OBJECT (demux, "Parse error");
-        }
+        err = gst_asf_demux_parse_packet (demux, buf);
 
         gst_buffer_unref (buf);
 
-        ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
+        if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
+          ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
+        else
+          GST_WARNING_OBJECT (demux, "Parse error");
 
         if (demux->packet >= 0)
           ++demux->packet;
@@ -1936,32 +2424,6 @@ gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
   return ret;
 }
 
-static inline guint32
-gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
-{
-  switch (type) {
-    case 0:
-      return 0;
-
-    case 1:
-      g_assert (*p_size >= 1);
-      return gst_asf_demux_get_uint8 (p_data, p_size);
-
-    case 2:
-      g_assert (*p_size >= 2);
-      return gst_asf_demux_get_uint16 (p_data, p_size);
-
-    case 3:
-      g_assert (*p_size >= 4);
-      return gst_asf_demux_get_uint32 (p_data, p_size);
-
-    default:
-      g_assert_not_reached ();
-      break;
-  }
-  return 0;
-}
-
 static gboolean
 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
     guint8 ** p_data, guint64 * p_size)
@@ -2062,6 +2524,11 @@ gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
   /* Codec specific data size */
   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
+  if (audio->size > *p_size) {
+    GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
+        G_GUINT64_FORMAT " long)", audio->size, *p_size);
+    return FALSE;
+  }
   return TRUE;
 }
 
@@ -2087,6 +2554,15 @@ gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
     return FALSE;
 
   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
+  /* Sanity checks */
+  if (fmt->size < 40) {
+    GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
+    return FALSE;
+  }
+  if ((guint64) fmt->size - 4 > *p_size) {
+    GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
+    return FALSE;
+  }
   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
@@ -2110,13 +2586,15 @@ gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
       return &demux->stream[i];
   }
 
-  GST_WARNING ("Segment found for undefined stream: (%d)", id);
+  if (gst_asf_demux_is_unknown_stream (demux, id))
+    GST_WARNING ("Segment found for undefined stream: (%d)", id);
   return NULL;
 }
 
-static void
+static AsfStream *
 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
-    GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
+    GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
+    GstTagList * tags)
 {
   AsfStream *stream;
 
@@ -2136,6 +2614,12 @@ gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
   stream->is_video = is_video;
   stream->pending_tags = tags;
   stream->discont = TRUE;
+  stream->first_buffer = TRUE;
+  stream->streamheader = streamheader;
+  if (stream->streamheader) {
+    stream->streamheader = gst_buffer_make_writable (streamheader);
+    GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
+  }
   if (is_video) {
     GstStructure *st;
     gint par_x, par_y;
@@ -2150,15 +2634,36 @@ gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
 
   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
 
+  /* TODO: create this array during reverse play? */
+  stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
+
   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
       GST_PAD_NAME (src_pad), demux->num_streams, caps);
 
   ++demux->num_streams;
 
   stream->active = FALSE;
+
+  return stream;
 }
 
 static void
+gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
+    GstBuffer * buffer, GstStructure * structure)
+{
+  GValue arr_val = G_VALUE_INIT;
+  GValue buf_val = G_VALUE_INIT;
+
+  g_value_init (&arr_val, GST_TYPE_ARRAY);
+  g_value_init (&buf_val, GST_TYPE_BUFFER);
+
+  gst_value_set_buffer (&buf_val, buffer);
+  gst_value_array_append_and_take_value (&arr_val, &buf_val);
+
+  gst_structure_take_value (structure, "streamheader", &arr_val);
+}
+
+static AsfStream *
 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
 {
@@ -2178,7 +2683,7 @@ gst_asf_demux_add_audio_stream (GstASFDemux * demux,
   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
   g_free (name);
 
-  /* Swallow up any left over data and set up the 
+  /* Swallow up any left over data and set up the
    * standard properties from the header info */
   if (size_left) {
     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
@@ -2205,6 +2710,27 @@ gst_asf_demux_add_audio_stream (GstASFDemux * demux,
     g_free (codec_name);
   }
 
+  if (audio->byte_rate > 0) {
+    /* Some ASF files have no bitrate props object (often seen with
+     * ASF files that contain raw audio data). Example files can
+     * be generated with FFmpeg (tested with v2.8.6), like this:
+     *
+     *   ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
+     *
+     * In this case, if audio->byte_rate is nonzero, use that as
+     * the bitrate. */
+
+    guint bitrate = audio->byte_rate * 8;
+
+    if (tags == NULL)
+      tags = gst_tag_list_new_empty ();
+
+    /* Add bitrate, but only if there is none set already, since
+     * this is just a fallback in case there is no bitrate tag
+     * already present */
+    gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
+  }
+
   if (extradata)
     gst_buffer_unref (extradata);
 
@@ -2214,21 +2740,33 @@ gst_asf_demux_add_audio_stream (GstASFDemux * demux,
 
   ++demux->num_audio_streams;
 
-  gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
+#ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
+  if (tags) {
+    /* post now, send event on pad later */
+    gst_element_post_message (GST_ELEMENT_CAST (demux),
+        gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
+  }
+#endif
+
+  return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
 }
 
-static void
+static AsfStream *
 gst_asf_demux_add_video_stream (GstASFDemux * demux,
     asf_stream_video_format * video, guint16 id,
     guint8 ** p_data, guint64 * p_size)
 {
   GstTagList *tags = NULL;
+  GstStructure *caps_s;
   GstBuffer *extradata = NULL;
   GstPad *src_pad;
   GstCaps *caps;
+  gchar *str;
   gchar *name = NULL;
   gchar *codec_name = NULL;
-  gint size_left = video->size - 40;
+  guint64 size_left = video->size - 40;
+  GstBuffer *streamheader = NULL;
+  guint par_w = 1, par_h = 1;
 
   /* Create the video pad */
   name = g_strdup_printf ("video_%u", demux->num_video_streams);
@@ -2237,7 +2775,9 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
 
   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
   if (size_left) {
-    GST_LOG ("Video header has %d bytes of codec specific data", size_left);
+    GST_LOG ("Video header has %" G_GUINT64_FORMAT
+        " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
+        *p_size);
     g_assert (size_left <= *p_size);
     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
   }
@@ -2258,9 +2798,10 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
     s = gst_asf_demux_get_metadata_for_stream (demux, id);
     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
         gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
+      par_w = ax;
+      par_h = ay;
       gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
           ax, ay, NULL);
-
     } else {
       guint ax, ay;
       /* retry with the global metadata */
@@ -2270,17 +2811,132 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
       if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
           gst_structure_get_uint (s, "AspectRatioY", &ay)) {
         GST_DEBUG ("ax:%d, ay:%d", ax, ay);
-        if (ax > 0 && ay > 0)
+        if (ax > 0 && ay > 0) {
+          par_w = ax;
+          par_h = ay;
           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
               ax, ay, NULL);
+        }
       }
     }
     s = gst_caps_get_structure (caps, 0);
     gst_structure_remove_field (s, "framerate");
   }
 
-  /* add fourcc format to caps, some proprietary decoders seem to need it */
-  gst_caps_set_simple (caps, "format", G_TYPE_UINT, video->tag, NULL);
+  caps_s = gst_caps_get_structure (caps, 0);
+
+  /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
+  if (gst_structure_has_name (caps_s, "video/x-wmv")) {
+    str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
+    gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
+    g_free (str);
+
+    /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
+  } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
+    const GValue *value = gst_structure_get_value (caps_s, "codec_data");
+    if (value) {
+      GstBuffer *buf = gst_value_get_buffer (value);
+      GstMapInfo mapinfo;
+
+      if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
+        if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
+          /* this looks like a bytestream start */
+          streamheader = gst_buffer_ref (buf);
+          gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
+          gst_structure_remove_field (caps_s, "codec_data");
+          gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
+              "byte-stream", NULL);
+        } else {
+          gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
+              NULL);
+        }
+
+        gst_buffer_unmap (buf, &mapinfo);
+      }
+    } else {
+      gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
+          NULL);
+    }
+  }
+
+  /* For a 3D video, set multiview information into the caps based on
+   * what was detected during object parsing */
+  if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
+    GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+    GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+    const gchar *mview_mode_str;
+
+    switch (demux->asf_3D_mode) {
+      case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+        break;
+      case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+        mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+        break;
+      case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+        break;
+      case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+        mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+        break;
+      case GST_ASF_3D_DUAL_STREAM:{
+        gboolean is_right_view = FALSE;
+        /* if Advanced_Mutual_Exclusion object exists, use it
+         * to figure out which is the left view (lower ID) */
+        if (demux->mut_ex_streams != NULL) {
+          guint length;
+          gint i;
+
+          length = g_slist_length (demux->mut_ex_streams);
+
+          for (i = 0; i < length; i++) {
+            gpointer v_s_id;
+
+            v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
+
+            GST_DEBUG_OBJECT (demux,
+                "has Mutual_Exclusion object. stream id in object is %d",
+                GPOINTER_TO_INT (v_s_id));
+
+            if (id > GPOINTER_TO_INT (v_s_id))
+              is_right_view = TRUE;
+          }
+        } else {
+          /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
+           * first video stream encountered has the lower ID */
+          if (demux->num_video_streams > 0) {
+            /* This is not the first video stream, assuming right eye view */
+            is_right_view = TRUE;
+          }
+        }
+        if (is_right_view)
+          mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
+        else
+          mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
+        break;
+      }
+      default:
+        break;
+    }
+
+    GST_INFO_OBJECT (demux,
+        "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
+        (guint) mv_flags);
+
+    mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
+    if (mview_mode_str != NULL) {
+      if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
+              video->height, par_w, par_h))
+        mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
+
+      gst_caps_set_simple (caps,
+          "multiview-mode", G_TYPE_STRING, mview_mode_str,
+          "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
+          GST_FLAG_SET_MASK_EXACT, NULL);
+    }
+  }
 
   if (codec_name) {
     tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
@@ -2296,18 +2952,56 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
 
   ++demux->num_video_streams;
 
-  gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
+#ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
+  if (tags) {
+    /* post now, send event on pad later */
+    gst_element_post_message (GST_ELEMENT_CAST (demux),
+        gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
+  }
+#endif
+
+  return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
+      streamheader, tags);
 }
 
 static void
 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
 {
   if (!stream->active) {
+    GstEvent *event;
+    gchar *stream_id;
+
     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
     gst_pad_set_active (stream->pad, TRUE);
+
+    stream_id =
+        gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
+        "%03u", stream->id);
+
+    event =
+        gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
+    if (event) {
+      if (gst_event_parse_group_id (event, &demux->group_id))
+        demux->have_group_id = TRUE;
+      else
+        demux->have_group_id = FALSE;
+      gst_event_unref (event);
+    } else if (!demux->have_group_id) {
+      demux->have_group_id = TRUE;
+      demux->group_id = gst_util_group_id_next ();
+    }
+
+    event = gst_event_new_stream_start (stream_id);
+    if (demux->have_group_id)
+      gst_event_set_group_id (event, demux->group_id);
+
+    gst_pad_push_event (stream->pad, event);
+    g_free (stream_id);
     gst_pad_set_caps (stream->pad, stream->caps);
+
     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
+    gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
     stream->active = TRUE;
   }
 }
@@ -2326,6 +3020,8 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
   guint stream_specific_size;
   guint type_specific_size G_GNUC_UNUSED;
   guint unknown G_GNUC_UNUSED;
+  gboolean inspect_payload = FALSE;
+  AsfStream *stream = NULL;
 
   /* Get the rest of the header's header */
   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
@@ -2344,12 +3040,31 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
 
   flags = gst_asf_demux_get_uint16 (&data, &size);
   stream_id = flags & 0x7f;
-  is_encrypted = ! !((flags & 0x8000) << 15);
+  is_encrypted = ! !(flags & 0x8000);
   unknown = gst_asf_demux_get_uint32 (&data, &size);
 
   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
       stream_id, GST_TIME_ARGS (time_offset));
 
+  /* dvr-ms has audio stream declared in stream specific data */
+  if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
+    AsfExtStreamType ext_stream_type;
+    gst_asf_demux_get_guid (&guid, &data, &size);
+    ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
+
+    if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
+      inspect_payload = TRUE;
+
+      gst_asf_demux_get_guid (&guid, &data, &size);
+      gst_asf_demux_get_uint32 (&data, &size);
+      gst_asf_demux_get_uint32 (&data, &size);
+      gst_asf_demux_get_uint32 (&data, &size);
+      gst_asf_demux_get_guid (&guid, &data, &size);
+      gst_asf_demux_get_uint32 (&data, &size);
+      stream_type = ASF_STREAM_AUDIO;
+    }
+  }
+
   switch (stream_type) {
     case ASF_STREAM_AUDIO:{
       asf_stream_audio audio_object;
@@ -2360,7 +3075,7 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
       GST_INFO ("Object is an audio stream with %u bytes of additional data",
           audio_object.size);
 
-      gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
+      stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
           &data, &size);
 
       switch (correction_type) {
@@ -2378,26 +3093,25 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
           data_size = gst_asf_demux_get_uint16 (&data, &size);
           silence_data = gst_asf_demux_get_uint8 (&data, &size);
 
-          /* FIXME: shouldn't this be per-stream? */
-          demux->span = span;
+          stream->span = span;
 
           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
               packet_size, chunk_size, data_size, span, silence_data);
 
-          if (demux->span > 1) {
+          if (stream->span > 1) {
             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
               /* Disable descrambling */
-              demux->span = 0;
+              stream->span = 0;
             } else {
               /* FIXME: this else branch was added for
                * weird_al_yankovic - the saga begins.asf */
-              demux->ds_packet_size = packet_size;
-              demux->ds_chunk_size = chunk_size;
+              stream->ds_packet_size = packet_size;
+              stream->ds_chunk_size = chunk_size;
             }
           } else {
             /* Descambling is enabled */
-            demux->ds_packet_size = packet_size;
-            demux->ds_chunk_size = chunk_size;
+            stream->ds_packet_size = packet_size;
+            stream->ds_chunk_size = chunk_size;
           }
 #if 0
           /* Now skip the rest of the silence data */
@@ -2445,9 +3159,17 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
               &data, &size)) {
         goto not_enough_data;
       }
-
-      gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
-          &data, &size);
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+      /* Compare video format WMV*, WVC* */
+      if (((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('M')<<8|('V')<<16))
+          || ((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('V')<<8|('C')<<16))) {
+          GST_ERROR_OBJECT (demux, "WMV file format is not supported.");
+          demux->is_supported_format = FALSE;
+          return NULL;
+      }
+#endif
+      stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
+          stream_id, &data, &size);
 
       break;
     }
@@ -2455,10 +3177,16 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
     default:
       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
           stream_id);
+      demux->other_streams =
+          g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
       break;
   }
 
-  return gst_asf_demux_get_stream (demux, stream_id);
+  if (stream) {
+    stream->inspect_payload = inspect_payload;
+    stream->type = stream_type;
+  }
+  return stream;
 
 not_enough_data:
   {
@@ -2483,7 +3211,7 @@ gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
     "WM/Picture", GST_TAG_IMAGE}, {
     "WM/Track", GST_TAG_TRACK_NUMBER}, {
     "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
-    "WM/Year", GST_TAG_DATE}
+    "WM/Year", GST_TAG_DATE_TIME}
     /* { "WM/Composer", GST_TAG_COMPOSER } */
   };
   gsize out;
@@ -2518,20 +3246,22 @@ gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
     return;
 
   if (gst_tag_list_is_empty (taglist)) {
-    gst_tag_list_free (taglist);
+    gst_tag_list_unref (taglist);
     return;
   }
 
   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
+  gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
   if (demux->taglist)
-    gst_tag_list_free (demux->taglist);
-  gst_tag_list_free (taglist);
+    gst_tag_list_unref (demux->taglist);
+  gst_tag_list_unref (taglist);
   demux->taglist = t;
   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
 }
 
 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
+#define ASF_DEMUX_DATA_TYPE_BOOL                       2
 #define ASF_DEMUX_DATA_TYPE_DWORD           3
 
 static void
@@ -2600,7 +3330,20 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
 
   GstTagList *taglist;
   guint16 blockcount, i;
+  gboolean content3D = FALSE;
 
+  struct
+  {
+    const gchar *interleave_name;
+    GstASF3DMode interleaving_type;
+  } stereoscopic_layout_map[] = {
+    {
+    "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
+    "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
+    "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
+    "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
+    "DualStream", GST_ASF_3D_DUAL_STREAM}
+  };
   GST_INFO_OBJECT (demux, "object is an extended content description");
 
   taglist = gst_tag_list_new_empty ();
@@ -2662,13 +3405,12 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
             value_utf8[out] = '\0';
 
             if (gst_tag_name != NULL) {
-              if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
+              if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
                 guint year = atoi (value_utf8);
 
                 if (year > 0) {
-                  /* FIXME: really want a GDateTime with just the year field */
-                  g_value_init (&tag_value, G_TYPE_DATE);
-                  g_value_take_boxed (&tag_value, g_date_new_dmy (1, 1, year));
+                  g_value_init (&tag_value, GST_TYPE_DATE_TIME);
+                  g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
                 }
               } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
                 guint id3v1_genre_id;
@@ -2705,6 +3447,26 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
               GST_DEBUG ("Setting metadata");
               g_value_init (&tag_value, G_TYPE_STRING);
               g_value_set_string (&tag_value, value_utf8);
+              /* If we found a stereoscopic marker, look for StereoscopicLayout
+               * metadata */
+              if (content3D) {
+                guint i;
+                if (strncmp ("StereoscopicLayout", name_utf8,
+                        strlen (name_utf8)) == 0) {
+                  for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
+                    if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
+                            value_utf8)) {
+                      demux->asf_3D_mode =
+                          stereoscopic_layout_map[i].interleaving_type;
+                      GST_INFO ("find interleave type %u", demux->asf_3D_mode);
+                    }
+                  }
+                }
+                GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
+              } else {
+                demux->asf_3D_mode = GST_ASF_3D_NONE;
+                GST_INFO_OBJECT (demux, "None 3d type");
+              }
             }
           } else if (value_utf8 == NULL) {
             GST_WARNING ("Failed to convert string value to UTF8, skipping");
@@ -2729,7 +3491,12 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
           break;
         }
         case ASF_DEMUX_DATA_TYPE_DWORD:{
-          guint uint_val = GST_READ_UINT32_LE (value);
+          guint uint_val;
+
+          if (value_len < 4)
+            break;
+
+          uint_val = GST_READ_UINT32_LE (value);
 
           /* this is the track number */
           g_value_init (&tag_value, G_TYPE_UINT);
@@ -2741,6 +3508,27 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
           g_value_set_uint (&tag_value, uint_val);
           break;
         }
+          /* Detect 3D */
+        case ASF_DEMUX_DATA_TYPE_BOOL:{
+          gboolean bool_val;
+
+          if (value_len < 4)
+            break;
+
+          bool_val = GST_READ_UINT32_LE (value);
+
+          if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
+            if (bool_val) {
+              GST_INFO_OBJECT (demux, "This is 3D contents");
+              content3D = TRUE;
+            } else {
+              GST_INFO_OBJECT (demux, "This is not 3D contenst");
+              content3D = FALSE;
+            }
+          }
+
+          break;
+        }
         default:{
           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
           break;
@@ -2784,7 +3572,7 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
 not_enough_data:
   {
     GST_WARNING ("Unexpected end of data parsing ext content desc object");
-    gst_tag_list_free (taglist);
+    gst_tag_list_unref (taglist);
     return GST_FLOW_OK;         /* not really fatal */
   }
 }
@@ -2905,7 +3693,7 @@ gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
   unknown = gst_asf_demux_get_uint8 (&data, &size);
 
   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
-
+  demux->saw_file_header = FALSE;
   /* Loop through the header's objects, processing those */
   for (i = 0; i < num_objects; ++i) {
     GST_INFO_OBJECT (demux, "reading header part %u", i);
@@ -2915,6 +3703,11 @@ gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
       break;
     }
   }
+  if (!demux->saw_file_header) {
+    GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+        ("Header does not have mandatory FILE section"));
+    return GST_FLOW_ERROR;
+  }
 
   return ret;
 
@@ -2995,6 +3788,8 @@ gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
       packets_count);
   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
 
+  demux->saw_file_header = TRUE;
+
   return GST_FLOW_OK;
 
 /* ERRORS */
@@ -3120,10 +3915,10 @@ gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
       GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
       stream = gst_asf_demux_get_stream (demux, stream_id);
       if (stream) {
-        if (stream->pending_tags == NULL) {
-          stream->pending_tags =
-              gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
-        }
+        if (stream->pending_tags == NULL)
+          stream->pending_tags = gst_tag_list_new_empty ();
+        gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_BITRATE, bitrate, NULL);
       } else {
         GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
       }
@@ -3229,6 +4024,7 @@ not_enough_data:
     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
     g_free (demux->languages);
     demux->languages = NULL;
+    demux->num_languages = 0;
     return GST_FLOW_OK;         /* not fatal */
   }
 }
@@ -3255,8 +4051,13 @@ gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
     demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
 
     for (i = 0; i < count; ++i) {
-      if (G_UNLIKELY (size <= 6))
+      if (G_UNLIKELY (size < 6)) {
+        /* adjust for broken files, to avoid having entries at the end
+         * of the parsed index that point to time=0. Resulting in seeking to
+         * the end of the file leading back to the beginning */
+        demux->sidx_num_entries -= (count - i);
         break;
+      }
       demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
       demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
@@ -3282,7 +4083,6 @@ gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
 {
   ASFGuid guid;
   guint16 num, i;
-  guint8 *mes;
 
   if (size < 16 + 2 + (2 * 2))
     goto not_enough_data;
@@ -3299,16 +4099,15 @@ gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
     goto not_enough_data;
 
   /* read mutually exclusive stream numbers */
-  mes = g_new (guint8, num + 1);
   for (i = 0; i < num; ++i) {
-    mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
-    GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
-  }
+    guint8 mes;
+    mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
+    GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
 
-  /* add terminator so we can easily get the count or know when to stop */
-  mes[i] = (guint8) - 1;
+    demux->mut_ex_streams =
+        g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
+  }
 
-  demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
 
   return GST_FLOW_OK;
 
@@ -3320,6 +4119,13 @@ not_enough_data:
   }
 }
 
+gboolean
+gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
+{
+  return g_slist_find (demux->other_streams,
+      GINT_TO_POINTER (stream_num)) == NULL;
+}
+
 static GstFlowReturn
 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
     guint64 size)
@@ -3338,6 +4144,8 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
   data_start = data;
   obj_size = (guint) size;
 
+  esp.payload_extensions = NULL;
+
   if (size < 64)
     goto not_enough_data;
 
@@ -3390,8 +4198,6 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
 
   if (num_payload_ext > 0)
     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
-  else
-    esp.payload_extensions = NULL;
 
   for (i = 0; i < num_payload_ext; ++i) {
     AsfPayloadExtension ext;
@@ -3423,9 +4229,12 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
     goto done;
   }
 
+  if (size < ASF_OBJECT_HEADER_SIZE)
+    goto not_enough_data;
+
   /* get size of the stream object */
   if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
-    goto not_enough_data;
+    goto corrupted_stream;
 
   if (stream_obj.id != ASF_OBJ_STREAM)
     goto expected_stream_object;
@@ -3446,6 +4255,13 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
   g_free (stream_obj_data);
 
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+  if ((stream == NULL) && (demux->is_supported_format == FALSE)) {
+    g_free (esp.payload_extensions);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+#endif
+
 done:
 
   if (stream) {
@@ -3486,16 +4302,20 @@ done:
           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
           NULL);
     }
-  } else {
+  } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
   }
 
+  if (!stream)
+    g_free (esp.payload_extensions);
+
   return GST_FLOW_OK;
 
   /* Errors */
 not_enough_data:
   {
     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
+    g_free (esp.payload_extensions);
     return GST_FLOW_OK;         /* not absolutely fatal */
   }
 expected_stream_object:
@@ -3503,8 +4323,15 @@ expected_stream_object:
     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
         "object: expected embedded stream object, but got %s object instead!",
         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
+    g_free (esp.payload_extensions);
     return GST_FLOW_OK;         /* not absolutely fatal */
   }
+corrupted_stream:
+  {
+    GST_WARNING_OBJECT (demux, "Corrupted stream");
+    g_free (esp.payload_extensions);
+    return GST_FLOW_ERROR;
+  }
 }
 
 static const gchar *
@@ -3638,7 +4465,9 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
   if (*p_size < ASF_OBJECT_HEADER_SIZE)
     return ASF_FLOW_NEED_MORE_DATA;
 
-  asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+  if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
+          TRUE))
+    return GST_FLOW_ERROR;
   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
 
   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
@@ -3653,6 +4482,12 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
   switch (obj.id) {
     case ASF_OBJ_STREAM:
       gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+      if (demux->is_supported_format == FALSE) {
+        ret = GST_FLOW_NOT_SUPPORTED;
+        break;
+      }
+#endif
       ret = GST_FLOW_OK;
       break;
     case ASF_OBJ_FILE:
@@ -3719,6 +4554,7 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
     case ASF_OBJ_INDEX_PARAMETERS:
     case ASF_OBJ_STREAM_PRIORITIZATION:
     case ASF_OBJ_SCRIPT_COMMAND:
+    case ASF_OBJ_METADATA_LIBRARY_OBJECT:
     default:
       /* Unknown/unhandled object, skip it and hope for the best */
       GST_INFO ("%s: skipping object", demux->objpath);
@@ -3761,29 +4597,29 @@ gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
   scrambled_buffer = *p_buffer;
 
   if (gst_buffer_get_size (scrambled_buffer) <
-      demux->ds_packet_size * demux->span)
+      stream->ds_packet_size * stream->span)
     return;
 
   for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
-      offset += demux->ds_chunk_size) {
-    off = offset / demux->ds_chunk_size;
-    row = off / demux->span;
-    col = off % demux->span;
-    idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
+      offset += stream->ds_chunk_size) {
+    off = offset / stream->ds_chunk_size;
+    row = off / stream->span;
+    col = off % stream->span;
+    idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
-        col, off, demux->ds_chunk_size);
+        col, off, stream->ds_chunk_size);
     GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
         ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
-        demux->span, demux->ds_packet_size);
+        stream->span, stream->ds_packet_size);
     GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
         gst_buffer_get_size (scrambled_buffer));
     sub_buffer =
-        gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
-        idx * demux->ds_chunk_size, demux->ds_chunk_size);
+        gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
+        idx * stream->ds_chunk_size, stream->ds_chunk_size);
     if (!offset) {
       descrambled_buffer = sub_buffer;
     } else {
-      descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
+      descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
     }
   }
 
@@ -3864,21 +4700,24 @@ gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
         break;
       }
 
-      GST_OBJECT_LOCK (demux);
+      res = gst_pad_query_default (pad, parent, query);
+      if (!res) {
+        GST_OBJECT_LOCK (demux);
 
-      if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
-        GST_LOG ("returning duration: %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (demux->segment.duration));
+        if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
+          GST_LOG ("returning duration: %" GST_TIME_FORMAT,
+              GST_TIME_ARGS (demux->segment.duration));
 
-        gst_query_set_duration (query, GST_FORMAT_TIME,
-            demux->segment.duration);
+          gst_query_set_duration (query, GST_FORMAT_TIME,
+              demux->segment.duration);
 
-        res = TRUE;
-      } else {
-        GST_LOG ("duration not known yet");
-      }
+          res = TRUE;
+        } else {
+          GST_LOG ("duration not known yet");
+        }
 
-      GST_OBJECT_UNLOCK (demux);
+        GST_OBJECT_UNLOCK (demux);
+      }
       break;
     }
 
@@ -3929,7 +4768,7 @@ gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
           GstFormat fmt;
           gboolean seekable;
 
-          /* try downstream first in TIME */
+          /* try upstream first in TIME */
           res = gst_pad_query_default (pad, parent, query);
 
           gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
@@ -3978,8 +4817,7 @@ gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
           GST_TIME_ARGS (min), GST_TIME_ARGS (max));
 
       GST_OBJECT_LOCK (demux);
-      if (min != -1)
-        min += demux->latency;
+      min += demux->latency;
       if (max != -1)
         max += demux->latency;
       GST_OBJECT_UNLOCK (demux);
@@ -3987,6 +4825,25 @@ gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
       gst_query_set_latency (query, live, min, max);
       break;
     }
+    case GST_QUERY_SEGMENT:
+    {
+      GstFormat format;
+      gint64 start, stop;
+
+      format = demux->segment.format;
+
+      start =
+          gst_segment_to_stream_time (&demux->segment, format,
+          demux->segment.start);
+      if ((stop = demux->segment.stop) == -1)
+        stop = demux->segment.duration;
+      else
+        stop = gst_segment_to_stream_time (&demux->segment, format, stop);
+
+      gst_query_set_segment (query, demux->segment.rate, format, start, stop);
+      res = TRUE;
+      break;
+    }
     default:
       res = gst_pad_query_default (pad, parent, query);
       break;
@@ -4006,6 +4863,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
       demux->need_newsegment = TRUE;
       demux->segment_running = FALSE;
+      demux->keyunit_sync = FALSE;
       demux->accurate = FALSE;
       demux->adapter = gst_adapter_new ();
       demux->metadata = gst_caps_new_empty ();
@@ -4014,6 +4872,8 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
       demux->data_offset = 0;
       demux->index_offset = 0;
       demux->base_offset = 0;
+      demux->flowcombiner = gst_flow_combiner_new ();
+
       break;
     }
     default:
@@ -4026,8 +4886,13 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_asf_demux_reset (demux, FALSE);
+      break;
+
     case GST_STATE_CHANGE_READY_TO_NULL:
       gst_asf_demux_reset (demux, FALSE);
+      gst_flow_combiner_free (demux->flowcombiner);
+      demux->flowcombiner = NULL;
       break;
     default:
       break;