asfdemux: Change the mismatched definition
[platform/upstream/gst-plugins-ugly.git] / gst / asfdemux / gstasfdemux.c
index 4e05db1..7940032 100644 (file)
@@ -101,7 +101,7 @@ static void
 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
     GstFlowReturn * pflow);
-static void gst_asf_demux_pull_indices (GstASFDemux * demux);
+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);
@@ -128,12 +128,12 @@ gst_asf_demux_class_init (GstASFDemuxClass * klass)
       "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);
@@ -175,6 +175,21 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
     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;
@@ -275,6 +290,7 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
     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");
     demux->data_size = 0;
@@ -303,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);
 }
@@ -412,6 +432,11 @@ gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       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);
@@ -427,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;
       }
 
@@ -622,7 +652,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
   GstSeekType cur_type, stop_type;
   GstFormat format;
   gboolean only_need_update;
-  gboolean accurate, after, before, next;
+  gboolean after, before, next;
   gboolean flush;
   gdouble rate;
   gint64 cur, stop;
@@ -631,6 +661,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
   gboolean eos;
   guint32 seqnum;
   GstEvent *fevent;
+  gint i;
 
   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
       &stop_type, &stop);
@@ -657,13 +688,17 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
   }
 
   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);
-  accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
+  demux->accurate =
+      ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
   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);
@@ -701,31 +736,17 @@ 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 */
-  fevent = gst_event_new_flush_stop (TRUE);
-  gst_event_set_seqnum (fevent, seqnum);
-  gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
-
-  if (G_LIKELY (flush))
+  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);
-  else
-    gst_event_unref (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_event_set_seqnum (newseg, seqnum);
-
-    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);
 
@@ -765,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 && (accurate || (demux->keyunit_sync && !next))
+      if (flush && (demux->accurate || (demux->keyunit_sync && !next))
           && demux->num_video_streams > 0) {
         seek_time -= 5 * GST_SECOND;
         if (seek_time < 0)
@@ -779,7 +800,7 @@ gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
         packet = demux->num_packets;
     }
   } else {
-    if (G_LIKELY (demux->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));
@@ -793,10 +814,17 @@ 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->segment_seqnum = seqnum;
-  demux->speed_packets = speed_count;
+  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);
 
@@ -862,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,
@@ -872,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;
 
@@ -880,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) {
@@ -889,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;
 }
 
@@ -911,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;
 
@@ -1016,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);
 
@@ -1060,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
@@ -1077,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;
@@ -1119,7 +1182,12 @@ 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;
 }
 
@@ -1141,14 +1209,19 @@ gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
 
   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,
@@ -1214,6 +1287,8 @@ parse_failed:
     if (buf)
       gst_buffer_unmap (buf, &map);
     gst_buffer_replace (&buf, NULL);
+    if (flow == ASF_FLOW_NEED_MORE_DATA)
+      flow = GST_FLOW_ERROR;
     *pflow = flow;
     return FALSE;
   }
@@ -1224,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);
@@ -1237,12 +1313,17 @@ all_streams_prerolled (GstASFDemux * demux)
     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;
     }
 
+    prerolled_types |= stream->type;
+
     /* find last payload with timestamp */
     for (last_idx = stream->payloads->len - 1;
         last_idx >= 0 && (last_payload == NULL
@@ -1260,6 +1341,13 @@ all_streams_prerolled (GstASFDemux * demux)
     }
   }
 
+  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;
 
@@ -1323,7 +1411,7 @@ gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
 }
 
 static gboolean
-gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
+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;
@@ -1354,26 +1442,24 @@ gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
 
       /* 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 
+         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) */
 
-      if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force)        /* still waiting for the second timestamp */
-        return FALSE;
+      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 we don't have timestamp for this stream, wait for more data */
-      if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
-        return FALSE;
-
       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 with force = TRUE */
+    if (!GST_CLOCK_TIME_IS_VALID (first_ts))    /* can happen */
       first_ts = 0;
 
     demux->first_ts = first_ts;
@@ -1462,19 +1548,19 @@ gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
 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;
 
-  if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
-    return FALSE;
-
   if (!all_streams_prerolled (demux) && !force) {
     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
     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];
 
@@ -1491,11 +1577,18 @@ gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
        * 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;
@@ -1529,46 +1622,77 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
       AsfPayload *payload = NULL;
       gint last_idx;
 
-      /* 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);
-      }
+      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 {
+          /* 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 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 there's a complete payload queued for this stream */
+          if (!gst_asf_payload_is_complete (payload))
+            continue;
 
-      if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
-              (payload->ts < demux->segment.start))) {
-        if (G_UNLIKELY (demux->keyunit_sync && 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;
         }
-      }
+      } 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 = 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);
-      }
+        /* 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);
+        }
 
-      if (!gst_asf_payload_is_complete (payload))
-        continue;
+        /* 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) {
@@ -1603,7 +1727,12 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
             && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
       return GST_FLOW_OK;
 
-    payload = &g_array_index (stream->payloads, AsfPayload, 0);
+    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))) {
@@ -1620,8 +1749,9 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
       }
 
       /* FIXME : only if ACCURATE ! */
-      if (G_LIKELY (demux->keyunit_sync
-              && 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;
@@ -1711,7 +1841,8 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
      * position reporting if a live src is playing not so live content
      * (e.g. rtspsrc taking some time to fall back to tcp) */
     timestamp = payload->ts;
-    if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    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
@@ -1749,6 +1880,15 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
     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) {
@@ -1775,7 +1915,18 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
       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))
@@ -1790,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");
@@ -1803,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;
@@ -1848,7 +2002,9 @@ gst_asf_demux_loop (GstASFDemux * demux)
       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);
@@ -1895,13 +2051,31 @@ gst_asf_demux_loop (GstASFDemux * demux)
 
       GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
       gst_buffer_unref (buf);
-      ++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;
+      }
+
       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;
@@ -1971,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) {
@@ -1998,9 +2172,14 @@ eos:
     }
 
     if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
-      /* 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 ());
+      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 */
   }
@@ -2012,11 +2191,12 @@ pause:
     gst_pad_pause_task (demux->sinkpad);
 
     /* For the error cases */
-    if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
+    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_ERROR (demux, STREAM, FAILED,
-          (_("Internal data stream error.")),
-          ("streaming stopped, reason %s", gst_flow_get_name (flow)));
+      GST_ELEMENT_FLOW_ERROR (demux, flow);
       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
     }
 
@@ -2057,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
@@ -2344,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;
 }
 
@@ -2369,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);
@@ -2440,6 +2634,9 @@ 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);
 
@@ -2486,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 "
@@ -2513,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);
 
@@ -2522,6 +2740,14 @@ gst_asf_demux_add_audio_stream (GstASFDemux * demux,
 
   ++demux->num_audio_streams;
 
+#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);
 }
 
@@ -2538,7 +2764,7 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
   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;
 
@@ -2549,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);
   }
@@ -2616,10 +2844,18 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
           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);
     }
   }
 
@@ -2716,6 +2952,14 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
 
   ++demux->num_video_streams;
 
+#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);
 }
@@ -2796,7 +3040,7 @@ 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,
@@ -2915,7 +3159,15 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
               &data, &size)) {
         goto not_enough_data;
       }
-
+#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);
 
@@ -2930,8 +3182,10 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
       break;
   }
 
-  if (stream)
+  if (stream) {
     stream->inspect_payload = inspect_payload;
+    stream->type = stream_type;
+  }
   return stream;
 
 not_enough_data:
@@ -3237,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);
@@ -3251,7 +3510,12 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
         }
           /* Detect 3D */
         case ASF_DEMUX_DATA_TYPE_BOOL:{
-          gboolean bool_val = GST_READ_UINT32_LE (value);
+          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) {
@@ -3429,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);
@@ -3439,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;
 
@@ -3519,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 */
@@ -3644,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);
       }
@@ -3753,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 */
   }
 }
@@ -3872,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;
 
@@ -3924,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;
@@ -3957,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;
@@ -3980,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) {
@@ -4024,12 +4306,16 @@ done:
     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:
@@ -4037,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 *
@@ -4172,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;
@@ -4187,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:
@@ -4563,6 +4864,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
       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 ();
       demux->global_metadata = gst_structure_new_empty ("metadata");
@@ -4571,6 +4873,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
       demux->index_offset = 0;
       demux->base_offset = 0;
       demux->flowcombiner = gst_flow_combiner_new ();
+
       break;
     }
     default: