Merge missing tizen patch
[platform/upstream/gstreamer.git] / libs / gst / base / gstbaseparse.c
index 7f29afa..0d765ec 100644 (file)
@@ -23,6 +23,7 @@
 
 /**
  * SECTION:gstbaseparse
+ * @title: GstBaseParse
  * @short_description: Base class for stream parsers
  * @see_also: #GstBaseTransform
  *
  * into separate audio/video/whatever frames.
  *
  * It provides for:
- * <itemizedlist>
- *   <listitem><para>provides one sink pad and one source pad</para></listitem>
- *   <listitem><para>handles state changes</para></listitem>
- *   <listitem><para>can operate in pull mode or push mode</para></listitem>
- *   <listitem><para>handles seeking in both modes</para></listitem>
- *   <listitem><para>handles events (SEGMENT/EOS/FLUSH)</para></listitem>
- *   <listitem><para>
- *        handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT)
- *   </para></listitem>
- *   <listitem><para>handles flushing</para></listitem>
- * </itemizedlist>
+ *
+ *   * provides one sink pad and one source pad
+ *   * handles state changes
+ *   * can operate in pull mode or push mode
+ *   * handles seeking in both modes
+ *   * handles events (SEGMENT/EOS/FLUSH)
+ *   * handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT)
+ *   * handles flushing
  *
  * The purpose of this base class is to provide the basic functionality of
  * a parser and share a lot of rather complex code.
  *
- * Description of the parsing mechanism:
- * <orderedlist>
- * <listitem>
- *   <itemizedlist><title>Set-up phase</title>
- *   <listitem><para>
- *     #GstBaseParse calls @start to inform subclass that data processing is
- *     about to start now.
- *   </para></listitem>
- *   <listitem><para>
- *     #GstBaseParse class calls @set_sink_caps to inform the subclass about
- *     incoming sinkpad caps. Subclass could already set the srcpad caps
- *     accordingly, but this might be delayed until calling
- *     gst_base_parse_finish_frame() with a non-queued frame.
- *   </para></listitem>
- *   <listitem><para>
- *      At least at this point subclass needs to tell the #GstBaseParse class
- *      how big data chunks it wants to receive (min_frame_size). It can do
- *      this with gst_base_parse_set_min_frame_size().
- *   </para></listitem>
- *   <listitem><para>
- *      #GstBaseParse class sets up appropriate data passing mode (pull/push)
- *      and starts to process the data.
- *   </para></listitem>
- *   </itemizedlist>
- * </listitem>
- * <listitem>
- *   <itemizedlist>
- *   <title>Parsing phase</title>
- *     <listitem><para>
- *       #GstBaseParse gathers at least min_frame_size bytes of data either
- *       by pulling it from upstream or collecting buffers in an internal
- *       #GstAdapter.
- *     </para></listitem>
- *     <listitem><para>
- *       A buffer of (at least) min_frame_size bytes is passed to subclass with
- *       @handle_frame. Subclass checks the contents and can optionally
- *       return GST_FLOW_OK along with an amount of data to be skipped to find
- *       a valid frame (which will result in a subsequent DISCONT).
- *       If, otherwise, the buffer does not hold a complete frame,
- *       @handle_frame can merely return and will be called again when additional
- *       data is available.  In push mode this amounts to an
- *       additional input buffer (thus minimal additional latency), in pull mode
- *       this amounts to some arbitrary reasonable buffer size increase.
- *       Of course, gst_base_parse_set_min_frame_size() could also be used if a
- *       very specific known amount of additional data is required.
- *       If, however, the buffer holds a complete valid frame, it can pass
- *       the size of this frame to gst_base_parse_finish_frame().
- *       If acting as a converter, it can also merely indicate consumed input data
- *       while simultaneously providing custom output data.
- *       Note that baseclass performs some processing (such as tracking
- *       overall consumed data rate versus duration) for each finished frame,
- *       but other state is only updated upon each call to @handle_frame
- *       (such as tracking upstream input timestamp).
- *       </para><para>
- *       Subclass is also responsible for setting the buffer metadata
- *       (e.g. buffer timestamp and duration, or keyframe if applicable).
- *       (although the latter can also be done by #GstBaseParse if it is
- *       appropriately configured, see below).  Frame is provided with
- *       timestamp derived from upstream (as much as generally possible),
- *       duration obtained from configuration (see below), and offset
- *       if meaningful (in pull mode).
- *       </para><para>
- *       Note that @check_valid_frame might receive any small
- *       amount of input data when leftover data is being drained (e.g. at EOS).
- *     </para></listitem>
- *     <listitem><para>
- *       As part of finish frame processing,
- *       just prior to actually pushing the buffer in question,
- *       it is passed to @pre_push_frame which gives subclass yet one
- *       last chance to examine buffer metadata, or to send some custom (tag)
- *       events, or to perform custom (segment) filtering.
- *     </para></listitem>
- *     <listitem><para>
- *       During the parsing process #GstBaseParseClass will handle both srcpad
- *       and sinkpad events. They will be passed to subclass if @event or
- *       @src_event callbacks have been provided.
- *     </para></listitem>
- *   </itemizedlist>
- * </listitem>
- * <listitem>
- *   <itemizedlist><title>Shutdown phase</title>
- *   <listitem><para>
- *     #GstBaseParse class calls @stop to inform the subclass that data
- *     parsing will be stopped.
- *   </para></listitem>
- *   </itemizedlist>
- * </listitem>
- * </orderedlist>
+ * # Description of the parsing mechanism:
+ *
+ * ## Set-up phase
+ *
+ *  * #GstBaseParse calls @start to inform subclass that data processing is
+ *    about to start now.
+ *
+ *  * #GstBaseParse class calls @set_sink_caps to inform the subclass about
+ *    incoming sinkpad caps. Subclass could already set the srcpad caps
+ *    accordingly, but this might be delayed until calling
+ *    gst_base_parse_finish_frame() with a non-queued frame.
+ *
+ *  * At least at this point subclass needs to tell the #GstBaseParse class
+ *    how big data chunks it wants to receive (min_frame_size). It can do
+ *    this with gst_base_parse_set_min_frame_size().
+ *
+ *  * #GstBaseParse class sets up appropriate data passing mode (pull/push)
+ *    and starts to process the data.
+ *
+ * ## Parsing phase
+ *
+ *  * #GstBaseParse gathers at least min_frame_size bytes of data either
+ *    by pulling it from upstream or collecting buffers in an internal
+ *    #GstAdapter.
+ *
+ *  * A buffer of (at least) min_frame_size bytes is passed to subclass with
+ *    @handle_frame. Subclass checks the contents and can optionally
+ *    return GST_FLOW_OK along with an amount of data to be skipped to find
+ *    a valid frame (which will result in a subsequent DISCONT).
+ *    If, otherwise, the buffer does not hold a complete frame,
+ *    @handle_frame can merely return and will be called again when additional
+ *    data is available.  In push mode this amounts to an
+ *    additional input buffer (thus minimal additional latency), in pull mode
+ *    this amounts to some arbitrary reasonable buffer size increase.
+ *    Of course, gst_base_parse_set_min_frame_size() could also be used if a
+ *    very specific known amount of additional data is required.
+ *    If, however, the buffer holds a complete valid frame, it can pass
+ *    the size of this frame to gst_base_parse_finish_frame().
+ *    If acting as a converter, it can also merely indicate consumed input data
+ *    while simultaneously providing custom output data.
+ *    Note that baseclass performs some processing (such as tracking
+ *    overall consumed data rate versus duration) for each finished frame,
+ *    but other state is only updated upon each call to @handle_frame
+ *    (such as tracking upstream input timestamp).
+ *
+ *    Subclass is also responsible for setting the buffer metadata
+ *    (e.g. buffer timestamp and duration, or keyframe if applicable).
+ *    (although the latter can also be done by #GstBaseParse if it is
+ *    appropriately configured, see below).  Frame is provided with
+ *    timestamp derived from upstream (as much as generally possible),
+ *    duration obtained from configuration (see below), and offset
+ *    if meaningful (in pull mode).
+ *
+ *    Note that @check_valid_frame might receive any small
+ *    amount of input data when leftover data is being drained (e.g. at EOS).
+ *
+ *  * As part of finish frame processing,
+ *    just prior to actually pushing the buffer in question,
+ *    it is passed to @pre_push_frame which gives subclass yet one
+ *    last chance to examine buffer metadata, or to send some custom (tag)
+ *    events, or to perform custom (segment) filtering.
+ *
+ *  * During the parsing process #GstBaseParseClass will handle both srcpad
+ *    and sinkpad events. They will be passed to subclass if @event or
+ *    @src_event callbacks have been provided.
+ *
+ * ## Shutdown phase
+ *
+ * * #GstBaseParse class calls @stop to inform the subclass that data
+ *   parsing will be stopped.
  *
  * Subclass is responsible for providing pad template caps for
  * source and sink pads. The pads need to be named "sink" and "src". It also
  * and end of data processing.
  *
  * Things that subclass need to take care of:
- * <itemizedlist>
- *   <listitem><para>Provide pad templates</para></listitem>
- *   <listitem><para>
- *      Fixate the source pad caps when appropriate
- *   </para></listitem>
- *   <listitem><para>
- *      Inform base class how big data chunks should be retrieved. This is
- *      done with gst_base_parse_set_min_frame_size() function.
- *   </para></listitem>
- *   <listitem><para>
- *      Examine data chunks passed to subclass with @handle_frame and pass
- *      proper frame(s) to gst_base_parse_finish_frame(), and setting src pad
- *      caps and timestamps on frame.
- *   </para></listitem>
- *   <listitem><para>Provide conversion functions</para></listitem>
- *   <listitem><para>
- *      Update the duration information with gst_base_parse_set_duration()
- *   </para></listitem>
- *   <listitem><para>
- *      Optionally passthrough using gst_base_parse_set_passthrough()
- *   </para></listitem>
- *   <listitem><para>
- *      Configure various baseparse parameters using
- *      gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable()
- *      and gst_base_parse_set_frame_rate().
- *   </para></listitem>
- *   <listitem><para>
- *      In particular, if subclass is unable to determine a duration, but
- *      parsing (or specs) yields a frames per seconds rate, then this can be
- *      provided to #GstBaseParse to enable it to cater for
- *      buffer time metadata (which will be taken from upstream as much as
- *      possible). Internally keeping track of frame durations and respective
- *      sizes that have been pushed provides #GstBaseParse with an estimated
- *      bitrate. A default @convert (used if not overridden) will then use these
- *      rates to perform obvious conversions.  These rates are also used to
- *      update (estimated) duration at regular frame intervals.
- *   </para></listitem>
- * </itemizedlist>
+ *
+ * * Provide pad templates
+ * * Fixate the source pad caps when appropriate
+ * * Inform base class how big data chunks should be retrieved. This is
+ *   done with gst_base_parse_set_min_frame_size() function.
+ * * Examine data chunks passed to subclass with @handle_frame and pass
+ *   proper frame(s) to gst_base_parse_finish_frame(), and setting src pad
+ *   caps and timestamps on frame.
+ * * Provide conversion functions
+ * * Update the duration information with gst_base_parse_set_duration()
+ * * Optionally passthrough using gst_base_parse_set_passthrough()
+ * * Configure various baseparse parameters using
+ *   gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable()
+ *   and gst_base_parse_set_frame_rate().
+ *
+ * * In particular, if subclass is unable to determine a duration, but
+ *   parsing (or specs) yields a frames per seconds rate, then this can be
+ *   provided to #GstBaseParse to enable it to cater for
+ *   buffer time metadata (which will be taken from upstream as much as
+ *   possible). Internally keeping track of frame durations and respective
+ *   sizes that have been pushed provides #GstBaseParse with an estimated
+ *   bitrate. A default @convert (used if not overridden) will then use these
+ *   rates to perform obvious conversions.  These rates are also used to
+ *   update (estimated) duration at regular frame intervals.
  *
  */
 
 #define MIN_FRAMES_TO_POST_BITRATE 10
 #define TARGET_DIFFERENCE          (20 * GST_SECOND)
 #define MAX_INDEX_ENTRIES          4096
+#define UPDATE_THRESHOLD           2
+
+#define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
 
 GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug);
 #define GST_CAT_DEFAULT gst_base_parse_debug
@@ -262,6 +231,7 @@ struct _GstBaseParsePrivate
   gboolean discont;
   gboolean flushing;
   gboolean drain;
+  gboolean saw_gaps;
 
   gint64 offset;
   gint64 sync_offset;
@@ -269,6 +239,7 @@ struct _GstBaseParsePrivate
   GstClockTime next_dts;
   GstClockTime prev_pts;
   GstClockTime prev_dts;
+  gboolean prev_dts_from_pts;
   GstClockTime frame_duration;
   gboolean seen_keyframe;
   gboolean is_video;
@@ -285,6 +256,7 @@ struct _GstBaseParsePrivate
   gboolean post_min_bitrate;
   gboolean post_avg_bitrate;
   gboolean post_max_bitrate;
+
   guint min_bitrate;
   guint avg_bitrate;
   guint max_bitrate;
@@ -355,6 +327,24 @@ struct _GstBaseParsePrivate
 
   /* if TRUE, a STREAM_START event needs to be pushed */
   gboolean push_stream_start;
+
+  /* When we need to skip more data than we have currently */
+  guint skip;
+
+  /* Tag handling (stream tags only, global tags are passed through as-is) */
+  GstTagList *upstream_tags;
+  GstTagList *parser_tags;
+  GstTagMergeMode parser_tags_merge_mode;
+  gboolean tags_changed;
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  /* to get pad mode early */
+  GstPadMode expected_pad_mode;
+  /* check first frame in base parser */
+  gboolean first_frame;
+  /* remove zero padding */
+  gint64 remove_from_total;
+  gboolean accurate_index_seek;
+#endif
 };
 
 typedef struct _GstBaseParseSeek
@@ -428,7 +418,8 @@ static gboolean gst_base_parse_sink_activate_mode (GstPad * pad,
     GstObject * parent, GstPadMode mode, gboolean active);
 static gboolean gst_base_parse_handle_seek (GstBaseParse * parse,
     GstEvent * event);
-static void gst_base_parse_handle_tag (GstBaseParse * parse, GstEvent * event);
+static void gst_base_parse_set_upstream_tags (GstBaseParse * parse,
+    GstTagList * taglist);
 
 static void gst_base_parse_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
@@ -463,11 +454,6 @@ static gboolean gst_base_parse_sink_query_default (GstBaseParse * parse,
 static gboolean gst_base_parse_src_query_default (GstBaseParse * parse,
     GstQuery * query);
 
-static void gst_base_parse_drain (GstBaseParse * parse);
-
-static void gst_base_parse_post_bitrates (GstBaseParse * parse,
-    gboolean post_min, gboolean post_avg, gboolean post_max);
-
 static gint64 gst_base_parse_find_offset (GstBaseParse * parse,
     GstClockTime time, gboolean before, GstClockTime * _ts);
 static GstFlowReturn gst_base_parse_locate_time (GstBaseParse * parse,
@@ -526,16 +512,6 @@ gst_base_parse_finalize (GObject * object)
 
   g_object_unref (parse->priv->adapter);
 
-  if (parse->priv->cache) {
-    gst_buffer_unref (parse->priv->cache);
-    parse->priv->cache = NULL;
-  }
-
-  g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
-      NULL);
-  g_list_free (parse->priv->pending_events);
-  parse->priv->pending_events = NULL;
-
   if (parse->priv->index) {
     gst_object_unref (parse->priv->index);
     parse->priv->index = NULL;
@@ -643,6 +619,10 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
 
   parse->priv->pad_mode = GST_PAD_MODE_NONE;
 
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  parse->priv->expected_pad_mode = GST_PAD_MODE_NONE;
+#endif
+
   g_mutex_init (&parse->priv->index_lock);
 
   /* init state */
@@ -650,6 +630,10 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
   GST_DEBUG_OBJECT (parse, "init ok");
 
   GST_OBJECT_FLAG_SET (parse, GST_ELEMENT_FLAG_INDEXABLE);
+
+  parse->priv->upstream_tags = NULL;
+  parse->priv->parser_tags = NULL;
+  parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
 }
 
 static void
@@ -684,7 +668,7 @@ gst_base_parse_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
-static GstBaseParseFrame *
+GstBaseParseFrame *
 gst_base_parse_frame_copy (GstBaseParseFrame * frame)
 {
   GstBaseParseFrame *copy;
@@ -766,11 +750,8 @@ gst_base_parse_frame_new (GstBuffer * buffer, GstBaseParseFrameFlags flags,
 }
 
 static inline void
-gst_base_parse_frame_update (GstBaseParse * parse, GstBaseParseFrame * frame,
-    GstBuffer * buf)
+gst_base_parse_update_flags (GstBaseParse * parse)
 {
-  gst_buffer_replace (&frame->buffer, buf);
-
   parse->flags = 0;
 
   /* set flags one by one for clarity */
@@ -782,6 +763,24 @@ gst_base_parse_frame_update (GstBaseParse * parse, GstBaseParseFrame * frame,
     parse->flags |= GST_BASE_PARSE_FLAG_LOST_SYNC;
 }
 
+static inline void
+gst_base_parse_update_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  if (G_UNLIKELY (parse->priv->discont)) {
+    GST_DEBUG_OBJECT (parse, "marking DISCONT");
+    GST_BUFFER_FLAG_SET (frame->buffer, GST_BUFFER_FLAG_DISCONT);
+  } else {
+    GST_BUFFER_FLAG_UNSET (frame->buffer, GST_BUFFER_FLAG_DISCONT);
+  }
+
+  if (parse->priv->prev_offset != parse->priv->offset || parse->priv->new_frame) {
+    GST_LOG_OBJECT (parse, "marking as new frame");
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME;
+  }
+
+  frame->offset = parse->priv->prev_offset = parse->priv->offset;
+}
+
 static void
 gst_base_parse_reset (GstBaseParse * parse)
 {
@@ -791,6 +790,7 @@ gst_base_parse_reset (GstBaseParse * parse)
   parse->priv->min_frame_size = 1;
   parse->priv->discont = TRUE;
   parse->priv->flushing = FALSE;
+  parse->priv->saw_gaps = FALSE;
   parse->priv->offset = 0;
   parse->priv->sync_offset = 0;
   parse->priv->update_interval = -1;
@@ -815,9 +815,6 @@ gst_base_parse_reset (GstBaseParse * parse)
   parse->priv->pts_interpolate = TRUE;
   parse->priv->infer_ts = TRUE;
   parse->priv->has_timing_info = FALSE;
-  parse->priv->post_min_bitrate = TRUE;
-  parse->priv->post_avg_bitrate = TRUE;
-  parse->priv->post_max_bitrate = TRUE;
   parse->priv->min_bitrate = G_MAXUINT;
   parse->priv->max_bitrate = 0;
   parse->priv->avg_bitrate = 0;
@@ -840,6 +837,14 @@ gst_base_parse_reset (GstBaseParse * parse)
   parse->priv->last_pts = GST_CLOCK_TIME_NONE;
   parse->priv->last_offset = 0;
 
+  parse->priv->skip = 0;
+
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  parse->priv->first_frame = TRUE;
+  parse->priv->remove_from_total = 0;
+  parse->priv->accurate_index_seek = TRUE;
+#endif
+
   g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
       NULL);
   g_list_free (parse->priv->pending_events);
@@ -857,6 +862,14 @@ gst_base_parse_reset (GstBaseParse * parse)
   if (parse->priv->adapter)
     gst_adapter_clear (parse->priv->adapter);
 
+  gst_base_parse_set_upstream_tags (parse, NULL);
+
+  if (parse->priv->parser_tags) {
+    gst_tag_list_unref (parse->priv->parser_tags);
+    parse->priv->parser_tags = NULL;
+  }
+  parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
+
   parse->priv->new_frame = TRUE;
 
   parse->priv->first_buffer = TRUE;
@@ -868,6 +881,86 @@ gst_base_parse_reset (GstBaseParse * parse)
   GST_OBJECT_UNLOCK (parse);
 }
 
+static gboolean
+gst_base_parse_check_bitrate_tag (GstBaseParse * parse, const gchar * tag)
+{
+  gboolean got_tag = FALSE;
+  guint n = 0;
+
+  if (parse->priv->upstream_tags != NULL)
+    got_tag = gst_tag_list_get_uint (parse->priv->upstream_tags, tag, &n);
+
+  if (!got_tag && parse->priv->parser_tags != NULL)
+    got_tag = gst_tag_list_get_uint (parse->priv->parser_tags, tag, &n);
+
+  return got_tag;
+}
+
+/* check if upstream or subclass tags contain bitrates already */
+static void
+gst_base_parse_check_bitrate_tags (GstBaseParse * parse)
+{
+  parse->priv->post_min_bitrate =
+      !gst_base_parse_check_bitrate_tag (parse, GST_TAG_MINIMUM_BITRATE);
+  parse->priv->post_avg_bitrate =
+      !gst_base_parse_check_bitrate_tag (parse, GST_TAG_BITRATE);
+  parse->priv->post_max_bitrate =
+      !gst_base_parse_check_bitrate_tag (parse, GST_TAG_MAXIMUM_BITRATE);
+}
+
+/* Queues new tag event with the current combined state of the stream tags
+ * (i.e. upstream tags merged with subclass tags and current baseparse tags) */
+static void
+gst_base_parse_queue_tag_event_update (GstBaseParse * parse)
+{
+  GstTagList *merged_tags;
+
+  GST_LOG_OBJECT (parse, "upstream : %" GST_PTR_FORMAT,
+      parse->priv->upstream_tags);
+  GST_LOG_OBJECT (parse, "parser   : %" GST_PTR_FORMAT,
+      parse->priv->parser_tags);
+  GST_LOG_OBJECT (parse, "mode     : %d", parse->priv->parser_tags_merge_mode);
+
+  merged_tags =
+      gst_tag_list_merge (parse->priv->upstream_tags, parse->priv->parser_tags,
+      parse->priv->parser_tags_merge_mode);
+
+  GST_DEBUG_OBJECT (parse, "merged   : %" GST_PTR_FORMAT, merged_tags);
+
+  if (merged_tags == NULL)
+    return;
+
+  if (gst_tag_list_is_empty (merged_tags)) {
+    gst_tag_list_unref (merged_tags);
+    return;
+  }
+
+  if (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE) {
+    /* only add bitrate tags to non-empty taglists for now, and only if neither
+     * upstream tags nor the subclass sets the bitrate tag in question already */
+    if (parse->priv->min_bitrate != G_MAXUINT && parse->priv->post_min_bitrate) {
+      GST_LOG_OBJECT (parse, "adding min bitrate %u", parse->priv->min_bitrate);
+      gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
+          GST_TAG_MINIMUM_BITRATE, parse->priv->min_bitrate, NULL);
+    }
+    if (parse->priv->max_bitrate != 0 && parse->priv->post_max_bitrate) {
+      GST_LOG_OBJECT (parse, "adding max bitrate %u", parse->priv->max_bitrate);
+      gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
+          GST_TAG_MAXIMUM_BITRATE, parse->priv->max_bitrate, NULL);
+    }
+    if (parse->priv->avg_bitrate != 0 && parse->priv->post_avg_bitrate) {
+      parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate;
+      GST_LOG_OBJECT (parse, "adding avg bitrate %u", parse->priv->avg_bitrate);
+      gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
+          GST_TAG_BITRATE, parse->priv->avg_bitrate, NULL);
+    }
+  }
+
+  parse->priv->pending_events =
+      g_list_prepend (parse->priv->pending_events,
+      gst_event_new_tag (merged_tags));
+}
+
 /* gst_base_parse_parse_frame:
  * @parse: #GstBaseParse.
  * @buffer: #GstBuffer.
@@ -948,6 +1041,84 @@ gst_base_parse_convert (GstBaseParse * parse,
   return ret;
 }
 
+static gboolean
+update_upstream_provided (GQuark field_id, const GValue * value,
+    gpointer user_data)
+{
+  GstCaps *default_caps = user_data;
+  gint i;
+  gint caps_size;
+
+  caps_size = gst_caps_get_size (default_caps);
+  for (i = 0; i < caps_size; i++) {
+    GstStructure *structure = gst_caps_get_structure (default_caps, i);
+    if (gst_structure_id_has_field (structure, field_id))
+      gst_structure_id_set_value (structure, field_id, value);
+  }
+
+  return TRUE;
+}
+
+static GstCaps *
+gst_base_parse_negotiate_default_caps (GstBaseParse * parse)
+{
+  GstCaps *caps, *templcaps;
+  GstCaps *sinkcaps = NULL;
+  GstCaps *default_caps = NULL;
+  GstStructure *structure;
+
+  templcaps = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse));
+  caps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), templcaps);
+  if (caps)
+    gst_caps_unref (templcaps);
+  else
+    caps = templcaps;
+  templcaps = NULL;
+
+  if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
+    goto caps_error;
+  }
+
+  GST_LOG_OBJECT (parse, "peer caps  %" GST_PTR_FORMAT, caps);
+
+  /* before fixating, try to use whatever upstream provided */
+  default_caps = gst_caps_copy (caps);
+  sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
+
+  GST_LOG_OBJECT (parse, "current caps %" GST_PTR_FORMAT " for sinkpad",
+      sinkcaps);
+
+  if (sinkcaps) {
+    structure = gst_caps_get_structure (sinkcaps, 0);
+    gst_structure_foreach (structure, update_upstream_provided, default_caps);
+  }
+
+  default_caps = gst_caps_fixate (default_caps);
+
+  if (!default_caps) {
+    GST_WARNING_OBJECT (parse, "Failed to create default caps !");
+    goto caps_error;
+  }
+
+  GST_INFO_OBJECT (parse,
+      "Chose default caps %" GST_PTR_FORMAT " for initial gap", default_caps);
+
+  if (sinkcaps)
+    gst_caps_unref (sinkcaps);
+  gst_caps_unref (caps);
+
+  return default_caps;
+
+caps_error:
+  {
+    if (caps)
+      gst_caps_unref (caps);
+    if (sinkcaps)
+      gst_caps_unref (sinkcaps);
+    return NULL;
+  }
+}
+
 /* gst_base_parse_sink_event:
  * @pad: #GstPad that received the event.
  * @event: #GstEvent to be handled.
@@ -968,7 +1139,6 @@ gst_base_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   return ret;
 }
 
-
 /* gst_base_parse_sink_event_default:
  * @parse: #GstBaseParse.
  * @event: #GstEvent to be handled.
@@ -1125,11 +1295,27 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
       parse->priv->last_dts = GST_CLOCK_TIME_NONE;
       parse->priv->prev_pts = GST_CLOCK_TIME_NONE;
       parse->priv->prev_dts = GST_CLOCK_TIME_NONE;
+      parse->priv->prev_dts_from_pts = FALSE;
       parse->priv->discont = TRUE;
       parse->priv->seen_keyframe = FALSE;
+      parse->priv->skip = 0;
       break;
     }
 
+    case GST_EVENT_SEGMENT_DONE:
+      /* need to drain now, rather than upon a new segment,
+       * since that would have SEGMENT_DONE come before potential
+       * delayed last part of the current segment */
+      GST_DEBUG_OBJECT (parse, "draining current segment");
+      if (parse->segment.rate > 0.0)
+        gst_base_parse_drain (parse);
+      else
+        gst_base_parse_finish_fragment (parse, FALSE);
+      /* Also forward event immediately, there might be no new data
+       * coming afterwards that would allow us to forward it later */
+      forward_immediate = TRUE;
+      break;
+
     case GST_EVENT_FLUSH_START:
       GST_OBJECT_LOCK (parse);
       parse->priv->flushing = TRUE;
@@ -1144,6 +1330,7 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
       parse->priv->last_pts = GST_CLOCK_TIME_NONE;
       parse->priv->last_dts = GST_CLOCK_TIME_NONE;
       parse->priv->new_frame = TRUE;
+      parse->priv->skip = 0;
 
       forward_immediate = TRUE;
       break;
@@ -1155,17 +1342,21 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
         gst_base_parse_finish_fragment (parse, TRUE);
 
       /* If we STILL have zero frames processed, fire an error */
-      if (parse->priv->framecount == 0) {
+      if (parse->priv->framecount == 0 && !parse->priv->saw_gaps &&
+          !parse->priv->first_buffer) {
         GST_ELEMENT_ERROR (parse, STREAM, WRONG_TYPE,
             ("No valid frames found before end of stream"), (NULL));
       }
-      /* newsegment and other serialized events before eos */
-      gst_base_parse_push_pending_events (parse);
 
-      if (parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE) {
+      if (!parse->priv->saw_gaps
+          && parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE) {
         /* We've not posted bitrate tags yet - do so now */
-        gst_base_parse_post_bitrates (parse, TRUE, TRUE, TRUE);
+        gst_base_parse_queue_tag_event_update (parse);
       }
+
+      /* newsegment and other serialized events before eos */
+      gst_base_parse_push_pending_events (parse);
+
       forward_immediate = TRUE;
       break;
     case GST_EVENT_CUSTOM_DOWNSTREAM:{
@@ -1196,6 +1387,47 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
     {
       GST_DEBUG_OBJECT (parse, "draining current data due to gap event");
 
+      /* Ensure we have caps before forwarding the event */
+      if (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GstCaps *default_caps = NULL;
+        if ((default_caps = gst_base_parse_negotiate_default_caps (parse))) {
+          GList *l;
+          GstEvent *caps_event = gst_event_new_caps (default_caps);
+
+          GST_DEBUG_OBJECT (parse,
+              "Store caps event to pending list for initial pre-rolling");
+
+          /* Events are in decreasing order. Go down the list until we
+           * find the first pre-CAPS event and insert our CAPS event there.
+           *
+           * There should be a SEGMENT event already, which is > CAPS */
+          for (l = parse->priv->pending_events; l; l = l->next) {
+            GstEvent *e = l->data;
+
+            if (GST_EVENT_TYPE (e) < GST_EVENT_CAPS) {
+              parse->priv->pending_events =
+                  g_list_insert_before (parse->priv->pending_events, l,
+                  caps_event);
+              break;
+            }
+          }
+          /* No pending event that is < CAPS, so we have to add it at the very
+           * end of the list */
+          if (!l) {
+            parse->priv->pending_events =
+                g_list_append (parse->priv->pending_events, caps_event);
+          }
+          gst_caps_unref (default_caps);
+        } else {
+          gst_event_unref (event);
+          event = NULL;
+          ret = FALSE;
+          GST_ELEMENT_ERROR (parse, STREAM, FORMAT, (NULL),
+              ("Parser output not negotiated before GAP event."));
+          break;
+        }
+      }
+
       gst_base_parse_push_pending_events (parse);
 
       if (parse->segment.rate > 0.0)
@@ -1203,18 +1435,36 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
       else
         gst_base_parse_finish_fragment (parse, TRUE);
       forward_immediate = TRUE;
+      parse->priv->saw_gaps = TRUE;
       break;
     }
     case GST_EVENT_TAG:
-      /* See if any bitrate tags were posted */
-      gst_base_parse_handle_tag (parse, event);
-      break;
+    {
+      GstTagList *tags = NULL;
 
+      gst_event_parse_tag (event, &tags);
+
+      /* We only care about stream tags here, global tags we just forward */
+      if (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_STREAM)
+        break;
+
+      gst_base_parse_set_upstream_tags (parse, tags);
+      gst_base_parse_queue_tag_event_update (parse);
+      parse->priv->tags_changed = FALSE;
+      gst_event_unref (event);
+      event = NULL;
+      ret = TRUE;
+      break;
+    }
     case GST_EVENT_STREAM_START:
+    {
       if (parse->priv->pad_mode != GST_PAD_MODE_PULL)
         forward_immediate = TRUE;
-      break;
 
+      gst_base_parse_set_upstream_tags (parse, NULL);
+      parse->priv->tags_changed = TRUE;
+      break;
+    }
     default:
       break;
   }
@@ -1234,10 +1484,8 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
     if (!GST_EVENT_IS_SERIALIZED (event) || forward_immediate) {
       ret = gst_pad_push_event (parse->srcpad, event);
     } else {
-      // GST_VIDEO_DECODER_STREAM_LOCK (decoder);
       parse->priv->pending_events =
           g_list_prepend (parse->priv->pending_events, event);
-      // GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
       ret = TRUE;
     }
   }
@@ -1449,11 +1697,23 @@ gst_base_parse_convert_default (GstBaseParse * parse,
     return TRUE;
   }
 
+  if (parse->priv->upstream_format != GST_FORMAT_BYTES) {
+    /* don't do byte format conversions if we're not really parsing
+     * a raw elementary stream, since we don't really have BYTES
+     * position / duration info */
+    if (src_format == GST_FORMAT_BYTES || dest_format == GST_FORMAT_BYTES)
+      goto no_slaved_conversions;
+  }
+
   /* need at least some frames */
   if (!parse->priv->framecount)
     goto no_framecount;
 
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  duration = parse->priv->acc_duration / GST_USECOND;
+#else
   duration = parse->priv->acc_duration / GST_MSECOND;
+#endif
   bytes = parse->priv->bytecount;
 
   if (G_UNLIKELY (!duration || !bytes))
@@ -1463,7 +1723,13 @@ gst_base_parse_convert_default (GstBaseParse * parse,
     if (dest_format == GST_FORMAT_TIME) {
       /* BYTES -> TIME conversion */
       GST_DEBUG_OBJECT (parse, "converting bytes -> time");
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+      src_value = src_value - parse->priv->remove_from_total;
+#endif
       *dest_value = gst_util_uint64_scale (src_value, duration, bytes);
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+      *dest_value /= GST_USECOND;
+#endif
       *dest_value *= GST_MSECOND;
       GST_DEBUG_OBJECT (parse, "conversion result: %" G_GINT64_FORMAT " ms",
           *dest_value / GST_MSECOND);
@@ -1474,8 +1740,13 @@ gst_base_parse_convert_default (GstBaseParse * parse,
   } else if (src_format == GST_FORMAT_TIME) {
     if (dest_format == GST_FORMAT_BYTES) {
       GST_DEBUG_OBJECT (parse, "converting time -> bytes");
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+      *dest_value = gst_util_uint64_scale (src_value / GST_USECOND, bytes,
+          duration);
+#else
       *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes,
           duration);
+#endif
       GST_DEBUG_OBJECT (parse,
           "time %" G_GINT64_FORMAT " ms in bytes = %" G_GINT64_FORMAT,
           src_value / GST_MSECOND, *dest_value);
@@ -1512,82 +1783,39 @@ no_duration_bytes:
         G_GUINT64_FORMAT, duration, bytes);
     return FALSE;
   }
-
-}
-
-static void
-gst_base_parse_update_duration (GstBaseParse * baseparse)
-{
-  GstPad *peer;
-  GstBaseParse *parse;
-
-  parse = GST_BASE_PARSE (baseparse);
-
-  peer = gst_pad_get_peer (parse->sinkpad);
-  if (peer) {
-    gboolean qres = FALSE;
-    gint64 ptot, dest_value;
-
-    qres = gst_pad_query_duration (peer, GST_FORMAT_BYTES, &ptot);
-    gst_object_unref (GST_OBJECT (peer));
-    if (qres) {
-      if (gst_base_parse_convert (parse, GST_FORMAT_BYTES, ptot,
-              GST_FORMAT_TIME, &dest_value)) {
-
-        /* inform if duration changed, but try to avoid spamming */
-        parse->priv->estimated_drift +=
-            dest_value - parse->priv->estimated_duration;
-        if (parse->priv->estimated_drift > GST_SECOND ||
-            parse->priv->estimated_drift < -GST_SECOND) {
-          gst_element_post_message (GST_ELEMENT (parse),
-              gst_message_new_duration_changed (GST_OBJECT (parse)));
-          parse->priv->estimated_drift = 0;
-        }
-        parse->priv->estimated_duration = dest_value;
-        GST_LOG_OBJECT (parse,
-            "updated estimated duration to %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (dest_value));
-      }
-    }
+no_slaved_conversions:
+  {
+    GST_DEBUG_OBJECT (parse,
+        "Can't do format conversions when upstream format is not BYTES");
+    return FALSE;
   }
 }
 
 static void
-gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min,
-    gboolean post_avg, gboolean post_max)
+gst_base_parse_update_duration (GstBaseParse * parse)
 {
-  GstTagList *taglist = NULL;
-
-  if (post_min && parse->priv->post_min_bitrate) {
-    taglist = gst_tag_list_new_empty ();
-
-    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
-        GST_TAG_MINIMUM_BITRATE, parse->priv->min_bitrate, NULL);
-  }
-
-  if (post_avg && parse->priv->post_avg_bitrate) {
-    if (taglist == NULL)
-      taglist = gst_tag_list_new_empty ();
-
-    parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate;
-    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
-        parse->priv->avg_bitrate, NULL);
-  }
+  gint64 ptot, dest_value;
 
-  if (post_max && parse->priv->post_max_bitrate) {
-    if (taglist == NULL)
-      taglist = gst_tag_list_new_empty ();
+  if (!gst_pad_peer_query_duration (parse->sinkpad, GST_FORMAT_BYTES, &ptot))
+    return;
 
-    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
-        GST_TAG_MAXIMUM_BITRATE, parse->priv->max_bitrate, NULL);
-  }
+  if (!gst_base_parse_convert (parse, GST_FORMAT_BYTES, ptot,
+          GST_FORMAT_TIME, &dest_value))
+    return;
 
-  GST_DEBUG_OBJECT (parse, "Updated bitrates. Min: %u, Avg: %u, Max: %u",
-      parse->priv->min_bitrate, parse->priv->avg_bitrate,
-      parse->priv->max_bitrate);
+  /* inform if duration changed, but try to avoid spamming */
+  parse->priv->estimated_drift += dest_value - parse->priv->estimated_duration;
 
-  if (taglist != NULL) {
-    gst_pad_push_event (parse->srcpad, gst_event_new_tag (taglist));
+  parse->priv->estimated_duration = dest_value;
+  GST_LOG_OBJECT (parse,
+      "updated estimated duration to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (dest_value));
+
+  if (parse->priv->estimated_drift > GST_SECOND ||
+      parse->priv->estimated_drift < -GST_SECOND) {
+    gst_element_post_message (GST_ELEMENT (parse),
+        gst_message_new_duration_changed (GST_OBJECT (parse)));
+    parse->priv->estimated_drift = 0;
   }
 }
 
@@ -1601,12 +1829,8 @@ gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min,
 static void
 gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
 {
-  /* Only update the tag on a 10 kbps delta */
-  static const gint update_threshold = 10000;
-
   guint64 data_len, frame_dur;
-  gint overhead, frame_bitrate, old_avg_bitrate;
-  gboolean update_min = FALSE, update_avg = FALSE, update_max = FALSE;
+  gint overhead, frame_bitrate;
   GstBuffer *buffer = frame->buffer;
 
   overhead = frame->overhead;
@@ -1634,7 +1858,7 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
     parse->priv->avg_bitrate = parse->priv->bitrate;
     /* spread this (confirmed) info ASAP */
     if (parse->priv->posted_avg_bitrate != parse->priv->avg_bitrate)
-      gst_base_parse_post_bitrates (parse, FALSE, TRUE, FALSE);
+      parse->priv->tags_changed = TRUE;
   }
 
   if (frame_dur)
@@ -1645,36 +1869,36 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
   GST_LOG_OBJECT (parse, "frame bitrate %u, avg bitrate %u", frame_bitrate,
       parse->priv->avg_bitrate);
 
-  if (parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE) {
-    goto exit;
-  } else if (parse->priv->framecount == MIN_FRAMES_TO_POST_BITRATE) {
-    /* always post all at threshold time */
-    update_min = update_max = update_avg = TRUE;
-  }
+  if (parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE)
+    return;
+
+  if (parse->priv->framecount == MIN_FRAMES_TO_POST_BITRATE &&
+      (parse->priv->post_min_bitrate || parse->priv->post_avg_bitrate
+          || parse->priv->post_max_bitrate))
+    parse->priv->tags_changed = TRUE;
 
   if (G_LIKELY (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE)) {
     if (frame_bitrate < parse->priv->min_bitrate) {
       parse->priv->min_bitrate = frame_bitrate;
-      update_min = TRUE;
+      if (parse->priv->post_min_bitrate)
+        parse->priv->tags_changed = TRUE;
     }
 
     if (frame_bitrate > parse->priv->max_bitrate) {
       parse->priv->max_bitrate = frame_bitrate;
-      update_max = TRUE;
+      if (parse->priv->post_max_bitrate)
+        parse->priv->tags_changed = TRUE;
     }
 
-    old_avg_bitrate = parse->priv->posted_avg_bitrate;
-    if ((gint) (old_avg_bitrate - parse->priv->avg_bitrate) > update_threshold
-        || (gint) (parse->priv->avg_bitrate - old_avg_bitrate) >
-        update_threshold)
-      update_avg = TRUE;
+    /* Only update the tag on a 2% change */
+    if (parse->priv->post_avg_bitrate && parse->priv->avg_bitrate) {
+      guint64 diffprev = gst_util_uint64_scale_int (100,
+          ABSDIFF (parse->priv->avg_bitrate, parse->priv->posted_avg_bitrate),
+          parse->priv->avg_bitrate);
+      if (diffprev >= UPDATE_THRESHOLD)
+        parse->priv->tags_changed = TRUE;
+    }
   }
-
-  if ((update_min || update_avg || update_max))
-    gst_base_parse_post_bitrates (parse, update_min, update_avg, update_max);
-
-exit:
-  return;
 }
 
 /**
@@ -1904,27 +2128,17 @@ gst_base_parse_prepare_frame (GstBaseParse * parse, GstBuffer * buffer)
       GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer),
       gst_buffer_get_size (buffer));
 
-  if (parse->priv->discont) {
-    GST_DEBUG_OBJECT (parse, "marking DISCONT");
-    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
-    parse->priv->discont = FALSE;
-  }
-
   GST_BUFFER_OFFSET (buffer) = parse->priv->offset;
 
-  frame = gst_base_parse_frame_new (buffer, 0, 0);
+  gst_base_parse_update_flags (parse);
 
-  /* also ensure to update state flags */
-  gst_base_parse_frame_update (parse, frame, buffer);
+  frame = gst_base_parse_frame_new (buffer, 0, 0);
   gst_buffer_unref (buffer);
+  gst_base_parse_update_frame (parse, frame);
 
-  if (parse->priv->prev_offset != parse->priv->offset || parse->priv->new_frame) {
-    GST_LOG_OBJECT (parse, "marking as new frame");
-    parse->priv->new_frame = FALSE;
-    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME;
-  }
-
-  frame->offset = parse->priv->prev_offset = parse->priv->offset;
+  /* clear flags for next frame */
+  parse->priv->discont = FALSE;
+  parse->priv->new_frame = FALSE;
 
   /* use default handler to provide initial (upstream) metadata */
   gst_base_parse_parse_frame (parse, frame);
@@ -1962,6 +2176,14 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
     gst_adapter_push (parse->priv->adapter, buffer);
   }
 
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  /* some one-time start-up */
+  if (G_UNLIKELY (parse->priv->framecount == 0)) {
+    gst_base_parse_check_seekability (parse);
+    gst_base_parse_check_upstream (parse);
+  }
+#endif
+
   frame = gst_base_parse_prepare_frame (parse, buffer);
   ret = klass->handle_frame (parse, frame, skip);
 
@@ -1993,7 +2215,20 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
           g_slist_prepend (parse->priv->buffers_head, outbuf);
       outbuf = NULL;
     } else {
-      gst_adapter_flush (parse->priv->adapter, *skip);
+      /* If we're asked to skip more than is available in the adapter,
+         we need to remember what we need to skip for next iteration */
+      gsize av = gst_adapter_available (parse->priv->adapter);
+      GST_DEBUG ("Asked to skip %u (%" G_GSIZE_FORMAT " available)", *skip, av);
+      if (av >= *skip) {
+        gst_adapter_flush (parse->priv->adapter, *skip);
+      } else {
+        GST_DEBUG
+            ("This is more than available, flushing %" G_GSIZE_FORMAT
+            ", storing %u to skip", av, (guint) (*skip - av));
+        parse->priv->skip = *skip - av;
+        gst_adapter_flush (parse->priv->adapter, av);
+        *skip = av;
+      }
     }
     if (!parse->priv->discont)
       parse->priv->sync_offset = parse->priv->offset;
@@ -2010,6 +2245,12 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
     gst_adapter_clear (parse->priv->adapter);
   }
 
+  if (*skip == 0 && *flushed == 0) {
+    /* Carry over discont if we need more data */
+    if (GST_BUFFER_IS_DISCONT (frame->buffer))
+      parse->priv->discont = TRUE;
+  }
+
   gst_base_parse_frame_free (frame);
 
   return ret;
@@ -2103,6 +2344,15 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse,
    * we may have new information on frame properties */
   gst_base_parse_parse_frame (parse, frame);
 
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  if (parse->priv->first_frame) {
+    parse->priv->remove_from_total = GST_BUFFER_OFFSET (buffer);
+    GST_DEBUG_OBJECT (parse, "first frame has offset %" G_GINT64_FORMAT ". remove from total",
+        parse->priv->remove_from_total);
+    parse->priv->first_frame = FALSE;
+  }
+#endif
+
   parse->priv->next_pts = GST_CLOCK_TIME_NONE;
   if (GST_BUFFER_DTS_IS_VALID (buffer) && GST_BUFFER_DURATION_IS_VALID (buffer)) {
     parse->priv->next_dts =
@@ -2169,6 +2419,13 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
 
   buffer = frame->buffer;
 
+#ifdef TIZEN_PROFILE_TV
+  if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer))) {
+    GST_LOG_OBJECT (parse, "invalid pts, set with dts");
+    GST_BUFFER_PTS (buffer) = GST_BUFFER_DTS (buffer);
+  }
+#endif
+
   GST_LOG_OBJECT (parse,
       "processing buffer of size %" G_GSIZE_FORMAT " with dts %" GST_TIME_FORMAT
       ", pts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
@@ -2189,7 +2446,11 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   if (parse->priv->update_interval < 0)
     parse->priv->update_interval = 50;
   else if (parse->priv->update_interval > 0 &&
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+      ((parse->priv->framecount - 1) % parse->priv->update_interval) == 0)
+#else
       (parse->priv->framecount % parse->priv->update_interval) == 0)
+#endif
     gst_base_parse_update_duration (parse);
 
   if (GST_BUFFER_PTS_IS_VALID (buffer))
@@ -2207,6 +2468,11 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     gst_base_parse_check_media (parse);
   }
 
+  if (parse->priv->tags_changed) {
+    gst_base_parse_queue_tag_event_update (parse);
+    parse->priv->tags_changed = FALSE;
+  }
+
   /* Push pending events, including SEGMENT events */
   gst_base_parse_push_pending_events (parse);
 
@@ -2254,6 +2520,14 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
   }
 
+  /* Push pending events, if there are any new ones
+   * like tags added by pre_push_frame */
+  if (parse->priv->tags_changed) {
+    gst_base_parse_queue_tag_event_update (parse);
+    parse->priv->tags_changed = FALSE;
+  }
+  gst_base_parse_push_pending_events (parse);
+
   /* take final ownership of frame buffer */
   if (frame->out_buffer) {
     buffer = frame->out_buffer;
@@ -2298,6 +2572,8 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
 
   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
     GST_LOG_OBJECT (parse, "frame (%" G_GSIZE_FORMAT " bytes) dropped", size);
+    if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
+      parse->priv->discont = TRUE;
     gst_buffer_unref (buffer);
     ret = GST_FLOW_OK;
   } else if (ret == GST_FLOW_OK) {
@@ -2354,8 +2630,9 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   }
 
   /* Update current running segment position */
-  if (ret == GST_FLOW_OK && last_stop != GST_CLOCK_TIME_NONE &&
-      parse->segment.position < last_stop)
+  if ((ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
+      && last_stop != GST_CLOCK_TIME_NONE
+      && parse->segment.position < last_stop)
     parse->segment.position = last_stop;
 
   return ret;
@@ -2467,13 +2744,17 @@ exit:
   return ret;
 }
 
-/* gst_base_parse_drain:
+/**
+ * gst_base_parse_drain:
+ * @parse: a #GstBaseParse
  *
  * Drains the adapter until it is empty. It decreases the min_frame_size to
  * match the current adapter size and calls chain method until the adapter
  * is emptied or chain returns with error.
+ *
+ * Since: 1.12
  */
-static void
+void
 gst_base_parse_drain (GstBaseParse * parse)
 {
   guint avail;
@@ -2531,6 +2812,12 @@ gst_base_parse_send_buffers (GstBaseParse * parse)
     if (first) {
       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
       first = FALSE;
+    } else {
+      /* likewise, subsequent buffers should never have DISCONT
+       * according to the "reverse fragment protocol", or such would
+       * confuse a downstream decoder
+       * (could be DISCONT due to aggregating upstream fragments by parsing) */
+      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
     }
 
     /* iterate output queue an push downstream */
@@ -2568,6 +2855,7 @@ gst_base_parse_start_fragment (GstBaseParse * parse)
   parse->priv->prev_pts = GST_CLOCK_TIME_NONE;
   parse->priv->next_dts = GST_CLOCK_TIME_NONE;
   parse->priv->prev_dts = GST_CLOCK_TIME_NONE;
+  parse->priv->prev_dts_from_pts = FALSE;
   /* prevent it hanging around stop all the time */
   parse->segment.position = GST_CLOCK_TIME_NONE;
   /* mark next run */
@@ -2781,12 +3069,35 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
   GstBuffer *tmpbuf = NULL;
   guint fsize = 1;
   gint skip = -1;
-  const guint8 *data;
   guint min_size, av;
   GstClockTime pts, dts;
 
   parse = GST_BASE_PARSE (parent);
   bclass = GST_BASE_PARSE_GET_CLASS (parse);
+  GST_DEBUG_OBJECT (parent, "chain");
+
+  /* early out for speed, if we need to skip */
+  if (buffer && GST_BUFFER_IS_DISCONT (buffer))
+    parse->priv->skip = 0;
+  if (parse->priv->skip > 0) {
+    gsize bsize = gst_buffer_get_size (buffer);
+    GST_DEBUG ("Got %" G_GSIZE_FORMAT " buffer, need to skip %u", bsize,
+        parse->priv->skip);
+    if (parse->priv->skip >= bsize) {
+      parse->priv->skip -= bsize;
+      GST_DEBUG ("All the buffer is skipped");
+      parse->priv->offset += bsize;
+      parse->priv->sync_offset = parse->priv->offset;
+      return GST_FLOW_OK;
+    }
+    buffer = gst_buffer_make_writable (buffer);
+    gst_buffer_resize (buffer, parse->priv->skip, bsize - parse->priv->skip);
+    parse->priv->offset += parse->priv->skip;
+    GST_DEBUG ("Done skipping, we have %u left on this buffer",
+        (unsigned) (bsize - parse->priv->skip));
+    parse->priv->skip = 0;
+    parse->priv->discont = TRUE;
+  }
 
   if (G_UNLIKELY (parse->priv->first_buffer)) {
     parse->priv->first_buffer = FALSE;
@@ -2895,13 +3206,17 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
       gst_base_parse_frame_free (&frame);
       return ret;
     }
-    /* upstream feeding us in reverse playback;
-     * finish previous fragment and start new upon DISCONT */
-    if (parse->segment.rate < 0.0) {
-      if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
+    if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
+      /* upstream feeding us in reverse playback;
+       * finish previous fragment and start new upon DISCONT */
+      if (parse->segment.rate < 0.0) {
         GST_DEBUG_OBJECT (parse, "buffer starts new reverse playback fragment");
         ret = gst_base_parse_finish_fragment (parse, TRUE);
         gst_base_parse_start_fragment (parse);
+      } else {
+        /* discont in the stream, drain and mark discont for next output */
+        gst_base_parse_drain (parse);
+        parse->priv->discont = TRUE;
       }
     }
     gst_adapter_push (parse->priv->adapter, buffer);
@@ -2911,6 +3226,7 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
   /* Stop either when adapter is empty or we are flushing */
   while (!parse->priv->flushing) {
     gint flush = 0;
+    gboolean updated_prev_pts = FALSE;
 
     /* note: if subclass indicates MAX fsize,
      * this will not likely be available anyway ... */
@@ -2935,11 +3251,15 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
      * but interpolate in between */
     pts = gst_adapter_prev_pts (parse->priv->adapter, NULL);
     dts = gst_adapter_prev_dts (parse->priv->adapter, NULL);
-    if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts))
+    if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts)) {
       parse->priv->prev_pts = parse->priv->next_pts = pts;
+      updated_prev_pts = TRUE;
+    }
 
-    if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts))
+    if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts)) {
       parse->priv->prev_dts = parse->priv->next_dts = dts;
+      parse->priv->prev_dts_from_pts = FALSE;
+    }
 
     /* we can mess with, erm interpolate, timestamps,
      * and incoming stuff has PTS but no DTS seen so far,
@@ -2947,31 +3267,29 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
     if (parse->priv->infer_ts &&
         parse->priv->pts_interpolate &&
         !GST_CLOCK_TIME_IS_VALID (dts) &&
-        !GST_CLOCK_TIME_IS_VALID (parse->priv->prev_dts) &&
-        GST_CLOCK_TIME_IS_VALID (pts))
-      parse->priv->next_dts = pts;
+        (!GST_CLOCK_TIME_IS_VALID (parse->priv->prev_dts)
+            || (parse->priv->prev_dts_from_pts && updated_prev_pts))
+        && GST_CLOCK_TIME_IS_VALID (pts)) {
+      parse->priv->prev_dts = parse->priv->next_dts = pts;
+      parse->priv->prev_dts_from_pts = TRUE;
+    }
 
     /* always pass all available data */
-    data = gst_adapter_map (parse->priv->adapter, av);
-    /* arrange for actual data to be copied if subclass tries to,
-     * since what is passed is tied to the adapter */
-    tmpbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY |
-        GST_MEMORY_FLAG_NO_SHARE, (gpointer) data, av, 0, av, NULL, NULL);
+    tmpbuf = gst_adapter_get_buffer (parse->priv->adapter, av);
 
     /* already inform subclass what timestamps we have planned,
      * at least if provided by time-based upstream */
     if (parse->priv->upstream_format == GST_FORMAT_TIME) {
+      tmpbuf = gst_buffer_make_writable (tmpbuf);
       GST_BUFFER_PTS (tmpbuf) = parse->priv->next_pts;
       GST_BUFFER_DTS (tmpbuf) = parse->priv->next_dts;
+      GST_BUFFER_DURATION (tmpbuf) = GST_CLOCK_TIME_NONE;
     }
 
     /* keep the adapter mapped, so keep track of what has to be flushed */
     ret = gst_base_parse_handle_buffer (parse, tmpbuf, &skip, &flush);
     tmpbuf = NULL;
 
-    /* probably already implicitly unmapped due to adapter operation,
-     * but for good measure ... */
-    gst_adapter_unmap (parse->priv->adapter);
     if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
       goto done;
     }
@@ -2982,7 +3300,8 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
       ret = old_ret;
       goto done;
     }
-    old_ret = ret;
+    if (old_ret == GST_FLOW_OK)
+      old_ret = ret;
   }
 
 done:
@@ -3194,6 +3513,12 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass)
     if (ret != GST_FLOW_OK)
       break;
 
+    /* If a large amount of data was requested to be skipped, _handle_buffer
+       might have set the priv->skip flag to an extra amount on top of skip.
+       In pull mode, we can just pull from the new offset directly. */
+    parse->priv->offset += parse->priv->skip;
+    parse->priv->skip = 0;
+
     /* something flushed means something happened,
      * and we should bail out of this loop so as not to occupy
      * the task thread indefinitely */
@@ -3264,8 +3589,6 @@ gst_base_parse_loop (GstPad * pad)
   }
 
   ret = gst_base_parse_scan_frame (parse, klass);
-  if (ret != GST_FLOW_OK)
-    goto done;
 
   /* eat expected eos signalling past segment in reverse playback */
   if (parse->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
@@ -3275,9 +3598,12 @@ gst_base_parse_loop (GstPad * pad)
     gst_base_parse_finish_fragment (parse, FALSE);
     /* force previous fragment */
     parse->priv->offset = -1;
-    ret = GST_FLOW_OK;
+    goto eos;
   }
 
+  if (ret != GST_FLOW_OK)
+    goto done;
+
 done:
   if (ret == GST_FLOW_EOS)
     goto eos;
@@ -3330,11 +3656,13 @@ pause:
       /* for fatal errors we post an error message, wrong-state is
        * not fatal because it happens due to flushes and only means
        * that we should stop now. */
-      GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
-          ("streaming stopped, reason %s", gst_flow_get_name (ret)));
+      GST_ELEMENT_FLOW_ERROR (parse, ret);
       push_eos = TRUE;
     }
     if (push_eos) {
+      if (parse->priv->estimated_duration <= 0) {
+        gst_base_parse_update_duration (parse);
+      }
       /* Push pending events, including SEGMENT events */
       gst_base_parse_push_pending_events (parse);
 
@@ -3377,6 +3705,8 @@ gst_base_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
     goto baseparse_push;
 
   parse->priv->push_stream_start = TRUE;
+  /* In pull mode, upstream is BYTES */
+  parse->priv->upstream_format = GST_FORMAT_BYTES;
 
   return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_base_parse_loop,
       sinkpad, NULL);
@@ -3415,6 +3745,7 @@ gst_base_parse_activate (GstBaseParse * parse, gboolean active)
       result = klass->stop (parse);
 
     parse->priv->pad_mode = GST_PAD_MODE_NONE;
+    parse->priv->upstream_format = GST_FORMAT_UNDEFINED;
   }
   GST_DEBUG_OBJECT (parse, "activate return: %d", result);
   return result;
@@ -3432,6 +3763,11 @@ gst_base_parse_sink_activate_mode (GstPad * pad, GstObject * parent,
   GST_DEBUG_OBJECT (parse, "sink %sactivate in %s mode",
       (active) ? "" : "de", gst_pad_mode_get_name (mode));
 
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+    /* to know early what is the mode */
+    parse->priv->expected_pad_mode = active ? mode : GST_PAD_MODE_NONE;
+#endif
+
   if (!gst_base_parse_activate (parse, active))
     goto activate_failed;
 
@@ -3705,6 +4041,9 @@ void
 gst_base_parse_set_latency (GstBaseParse * parse, GstClockTime min_latency,
     GstClockTime max_latency)
 {
+  g_return_if_fail (min_latency != GST_CLOCK_TIME_NONE);
+  g_return_if_fail (min_latency <= max_latency);
+
   GST_OBJECT_LOCK (parse);
   parse->priv->min_latency = min_latency;
   parse->priv->max_latency = max_latency;
@@ -3766,7 +4105,10 @@ gst_base_parse_src_query_default (GstBaseParse * parse, GstQuery * query)
       if (!res) {
         /* Fall back on interpreting segment */
         GST_OBJECT_LOCK (parse);
-        if (format == GST_FORMAT_BYTES) {
+        /* Only reply BYTES if upstream is in BYTES already, otherwise
+         * we're not in charge */
+        if (format == GST_FORMAT_BYTES
+            && parse->priv->upstream_format == GST_FORMAT_BYTES) {
           dest_value = parse->priv->offset;
           res = TRUE;
         } else if (format == parse->segment.format &&
@@ -3776,9 +4118,10 @@ gst_base_parse_src_query_default (GstBaseParse * parse, GstQuery * query)
           res = TRUE;
         }
         GST_OBJECT_UNLOCK (parse);
-        if (!res) {
+        if (!res && parse->priv->upstream_format == GST_FORMAT_BYTES) {
           /* no precise result, upstream no idea either, then best estimate */
-          /* priv->offset is updated in both PUSH/PULL modes */
+          /* priv->offset is updated in both PUSH/PULL modes, *iff* we're
+           * in charge of things */
           res = gst_base_parse_convert (parse,
               GST_FORMAT_BYTES, parse->priv->offset, format, &dest_value);
         }
@@ -3874,9 +4217,10 @@ gst_base_parse_src_query_default (GstBaseParse * parse, GstQuery * query)
 
         GST_OBJECT_LOCK (parse);
         /* add our latency */
-        if (min_latency != -1)
-          min_latency += parse->priv->min_latency;
-        if (max_latency != -1)
+        min_latency += parse->priv->min_latency;
+        if (max_latency == -1 || parse->priv->max_latency == -1)
+          max_latency = -1;
+        else
           max_latency += parse->priv->max_latency;
         GST_OBJECT_UNLOCK (parse);
 
@@ -4227,9 +4571,6 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
   if (rate < 0.0 && parse->priv->pad_mode == GST_PAD_MODE_PUSH)
     goto negative_rate;
 
-  if (rate < 0.0 && parse->priv->pad_mode == GST_PAD_MODE_PULL)
-    goto negative_rate_pull_mode;
-
   if (start_type != GST_SEEK_TYPE_SET ||
       (stop_type != GST_SEEK_TYPE_SET && stop_type != GST_SEEK_TYPE_NONE))
     goto wrong_type;
@@ -4251,24 +4592,52 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
 
   /* maybe we can be accurate for (almost) free */
   gst_base_parse_find_offset (parse, seeksegment.position, TRUE, &start_ts);
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+  if (parse->priv->accurate_index_seek) {
+    if (seeksegment.position <= start_ts + TARGET_DIFFERENCE) {
+      GST_DEBUG_OBJECT (parse, "accurate seek possible");
+      accurate = TRUE;
+    }
+  } else {
+    GST_DEBUG_OBJECT (parse, "accurate seek NOT possible");
+    accurate = FALSE;
+  }
+#else
   if (seeksegment.position <= start_ts + TARGET_DIFFERENCE) {
     GST_DEBUG_OBJECT (parse, "accurate seek possible");
     accurate = TRUE;
   }
+#endif
+
   if (accurate) {
-    GstClockTime startpos = seeksegment.position;
+    GstClockTime startpos;
+    if (rate >= 0)
+      startpos = seeksegment.position;
+    else
+      startpos = start;
 
     /* accurate requested, so ... seek a bit before target */
     if (startpos < parse->priv->lead_in_ts)
       startpos = 0;
     else
       startpos -= parse->priv->lead_in_ts;
+
+    if (seeksegment.stop == -1 && seeksegment.duration != -1)
+      seeksegment.stop = seeksegment.start + seeksegment.duration;
+
     seekpos = gst_base_parse_find_offset (parse, startpos, TRUE, &start_ts);
     seekstop = gst_base_parse_find_offset (parse, seeksegment.stop, FALSE,
         NULL);
   } else {
-    start_ts = seeksegment.position;
-    if (!gst_base_parse_convert (parse, format, seeksegment.position,
+    if (rate >= 0)
+      start_ts = seeksegment.position;
+    else
+      start_ts = start;
+
+    if (seeksegment.stop == -1 && seeksegment.duration != -1)
+      seeksegment.stop = seeksegment.start + seeksegment.duration;
+
+    if (!gst_base_parse_convert (parse, format, start_ts,
             GST_FORMAT_BYTES, &seekpos))
       goto convert_failed;
     if (!gst_base_parse_convert (parse, format, seeksegment.stop,
@@ -4322,10 +4691,6 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
       gst_pad_push_event (parse->srcpad, gst_event_ref (fevent));
       gst_pad_push_event (parse->sinkpad, fevent);
       gst_base_parse_clear_queues (parse);
-    } else {
-      /* keep track of our position */
-      seeksegment.base = gst_segment_to_running_time (&seeksegment,
-          seeksegment.format, parse->segment.position);
     }
 
     memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));
@@ -4432,12 +4797,6 @@ done:
   return res;
 
   /* ERRORS */
-negative_rate_pull_mode:
-  {
-    GST_FIXME_OBJECT (parse, "negative playback in pull mode needs fixing");
-    res = FALSE;
-    goto done;
-  }
 negative_rate:
   {
     GST_DEBUG_OBJECT (parse, "negative playback rates delegated upstream.");
@@ -4465,33 +4824,23 @@ convert_failed:
   }
 }
 
-/* Checks if bitrates are available from upstream tags so that we don't
- * override them later
- */
 static void
-gst_base_parse_handle_tag (GstBaseParse * parse, GstEvent * event)
+gst_base_parse_set_upstream_tags (GstBaseParse * parse, GstTagList * taglist)
 {
-  GstTagList *taglist = NULL;
-  guint tmp;
-
-  gst_event_parse_tag (event, &taglist);
-
-  /* We only care about stream tags here */
-  if (gst_tag_list_get_scope (taglist) != GST_TAG_SCOPE_STREAM)
+  if (taglist == parse->priv->upstream_tags)
     return;
 
-  if (gst_tag_list_get_uint (taglist, GST_TAG_MINIMUM_BITRATE, &tmp)) {
-    GST_DEBUG_OBJECT (parse, "upstream min bitrate %d", tmp);
-    parse->priv->post_min_bitrate = FALSE;
-  }
-  if (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &tmp)) {
-    GST_DEBUG_OBJECT (parse, "upstream avg bitrate %d", tmp);
-    parse->priv->post_avg_bitrate = FALSE;
-  }
-  if (gst_tag_list_get_uint (taglist, GST_TAG_MAXIMUM_BITRATE, &tmp)) {
-    GST_DEBUG_OBJECT (parse, "upstream max bitrate %d", tmp);
-    parse->priv->post_max_bitrate = FALSE;
+  if (parse->priv->upstream_tags) {
+    gst_tag_list_unref (parse->priv->upstream_tags);
+    parse->priv->upstream_tags = NULL;
   }
+
+  GST_INFO_OBJECT (parse, "upstream tags: %" GST_PTR_FORMAT, taglist);
+
+  if (taglist != NULL)
+    parse->priv->upstream_tags = gst_tag_list_ref (taglist);
+
+  gst_base_parse_check_bitrate_tags (parse);
 }
 
 #if 0
@@ -4610,6 +4959,114 @@ gst_base_parse_set_ts_at_offset (GstBaseParse * parse, gsize offset)
   if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts))
     parse->priv->prev_pts = parse->priv->next_pts = pts;
 
-  if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts))
+  if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts)) {
     parse->priv->prev_dts = parse->priv->next_dts = dts;
+    parse->priv->prev_dts_from_pts = FALSE;
+  }
+}
+
+/**
+ * gst_base_parse_merge_tags:
+ * @parse: a #GstBaseParse
+ * @tags: (allow-none): a #GstTagList to merge, or NULL to unset
+ *     previously-set tags
+ * @mode: the #GstTagMergeMode to use, usually #GST_TAG_MERGE_REPLACE
+ *
+ * Sets the parser subclass's tags and how they should be merged with any
+ * upstream stream tags. This will override any tags previously-set
+ * with gst_base_parse_merge_tags().
+ *
+ * Note that this is provided for convenience, and the subclass is
+ * not required to use this and can still do tag handling on its own.
+ *
+ * Since: 1.6
+ */
+void
+gst_base_parse_merge_tags (GstBaseParse * parse, GstTagList * tags,
+    GstTagMergeMode mode)
+{
+  g_return_if_fail (GST_IS_BASE_PARSE (parse));
+  g_return_if_fail (tags == NULL || GST_IS_TAG_LIST (tags));
+  g_return_if_fail (tags == NULL || mode != GST_TAG_MERGE_UNDEFINED);
+
+  GST_OBJECT_LOCK (parse);
+
+  if (tags != parse->priv->parser_tags) {
+    if (parse->priv->parser_tags) {
+      gst_tag_list_unref (parse->priv->parser_tags);
+      parse->priv->parser_tags = NULL;
+      parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
+    }
+    if (tags) {
+      parse->priv->parser_tags = gst_tag_list_ref (tags);
+      parse->priv->parser_tags_merge_mode = mode;
+    }
+
+    GST_DEBUG_OBJECT (parse, "setting parser tags to %" GST_PTR_FORMAT
+        " (mode %d)", tags, parse->priv->parser_tags_merge_mode);
+
+    gst_base_parse_check_bitrate_tags (parse);
+    parse->priv->tags_changed = TRUE;
+  }
+
+  GST_OBJECT_UNLOCK (parse);
+}
+
+#ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
+void
+gst_base_parse_get_upstream_size (GstBaseParse * parse,
+    gint64 * upstream_size)
+{
+  GST_BASE_PARSE_INDEX_LOCK (parse);
+  *upstream_size = parse->priv->upstream_size;
+  GST_INFO_OBJECT (parse, "get upstream_size for child parser : (%"G_GUINT64_FORMAT")",
+    parse->priv->upstream_size);
+  GST_BASE_PARSE_INDEX_UNLOCK (parse);
+}
+
+void
+gst_base_parse_get_index_last_offset (GstBaseParse * parse,
+    gint64 * index_last_offset)
+{
+  GST_BASE_PARSE_INDEX_LOCK (parse);
+  *index_last_offset = parse->priv->index_last_offset;
+  GST_INFO_OBJECT (parse, "get index_last_offset for child parser : (%"G_GUINT64_FORMAT")",
+    parse->priv->index_last_offset);
+  GST_BASE_PARSE_INDEX_UNLOCK (parse);
 }
+
+void
+gst_base_parse_get_index_last_ts (GstBaseParse * parse,
+    GstClockTime * index_last_ts)
+{
+  GST_BASE_PARSE_INDEX_LOCK (parse);
+  *index_last_ts = parse->priv->index_last_ts;
+  GST_INFO_OBJECT (parse, "get index_last_ts for child parser : (%"GST_TIME_FORMAT")",
+    GST_TIME_ARGS(parse->priv->index_last_ts));
+  GST_BASE_PARSE_INDEX_UNLOCK (parse);
+}
+
+void
+gst_base_parse_get_pad_mode (GstBaseParse * parse,
+    GstPadMode * pad_mode)
+{
+  GST_BASE_PARSE_INDEX_LOCK (parse);
+  *pad_mode = parse->priv->expected_pad_mode;
+  GST_INFO_OBJECT (parse, "get pad_mode for child parse: mode num (%d)",
+    parse->priv->expected_pad_mode);
+  GST_BASE_PARSE_INDEX_UNLOCK (parse);
+}
+/*
+ * Checks if accurate seek mode are avilable from sub-parse
+ */
+void
+gst_base_parse_set_seek_mode (GstBaseParse * parse, gboolean seek_mode)
+{
+  g_return_if_fail (parse != NULL);
+  parse->priv->accurate_index_seek = seek_mode;
+  if (seek_mode)
+    GST_INFO_OBJECT (parse, "accurate seek mode ON");
+  else
+    GST_INFO_OBJECT (parse, "accurate seek mode OFF - for HTTP SEEK");
+}
+#endif