Merge branch 'upstream/1.16' into tizen_gst_1.16.2
[platform/upstream/gstreamer.git] / plugins / elements / gstqueue2.c
index f227a2b..a2c9538 100644 (file)
@@ -118,6 +118,7 @@ enum
 #define DEFAULT_HIGH_WATERMARK     0.99
 #define DEFAULT_TEMP_REMOVE        TRUE
 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
+#define DEFAULT_USE_BITRATE_QUERY  TRUE
 
 enum
 {
@@ -140,6 +141,11 @@ enum
   PROP_TEMP_REMOVE,
   PROP_RING_BUFFER_MAX_SIZE,
   PROP_AVG_IN_RATE,
+  PROP_USE_BITRATE_QUERY,
+  PROP_BITRATE,
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  PROP_BUFFER_MODE,
+#endif
   PROP_LAST
 };
 
@@ -304,6 +310,9 @@ static void update_cur_level (GstQueue2 * queue, GstQueue2Range * range);
 static void update_in_rates (GstQueue2 * queue, gboolean force);
 static GstMessage *gst_queue2_get_buffering_message (GstQueue2 * queue);
 static void gst_queue2_post_buffering (GstQueue2 * queue);
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+static gboolean change_current_range(GstQueue2 * queue, GstQueue2Range *req_range, guint64 offset, guint length);
+#endif
 
 typedef enum
 {
@@ -413,6 +422,13 @@ gst_queue2_class_init (GstQueue2Class * klass)
           "Location to store temporary files in (Only read this property, "
           "use temp-template to configure the name template)",
           NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_USE_BITRATE_QUERY,
+      g_param_spec_boolean ("use-bitrate-query",
+          "Use bitrate from downstream query",
+          "Use a bitrate from a downstream query to estimate buffer duration if not provided",
+          DEFAULT_USE_BITRATE_QUERY,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+          G_PARAM_STATIC_STRINGS));
 
   /**
    * GstQueue2:temp-remove
@@ -447,6 +463,31 @@ gst_queue2_class_init (GstQueue2Class * klass)
           "Average input data rate (bytes/s)",
           0, G_MAXINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * GstQueue2:bitrate
+   *
+   * The value used to convert between byte and time values for limiting
+   * the size of the queue.  Values are taken from either the upstream tags
+   * or from the downstream bitrate query.
+   */
+  g_object_class_install_property (gobject_class, PROP_BITRATE,
+      g_param_spec_uint64 ("bitrate", "Bitrate (bits/s)",
+          "Conversion value between data size and time",
+          0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  /**
+   * GstQueue2:buffer-mode:
+   *
+   * Control the buffering mode used by the queue2.
+   */
+  g_object_class_install_property (gobject_class, PROP_BUFFER_MODE,
+      g_param_spec_enum ("buffer-mode", "Buffer Mode",
+          "Control the buffering algorithm in use",
+          GST_TYPE_BUFFERING_MODE, GST_BUFFERING_STREAM,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
   /* set several parent class virtual functions */
   gobject_class->finalize = gst_queue2_finalize;
 
@@ -541,6 +582,11 @@ gst_queue2_init (GstQueue2 * queue)
   queue->ring_buffer = NULL;
   queue->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
 
+  queue->use_bitrate_query = DEFAULT_USE_BITRATE_QUERY;
+
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  queue->mode = -1;
+#endif
   GST_DEBUG_OBJECT (queue,
       "initialized queue's not_empty & not_full conditions");
 }
@@ -600,6 +646,9 @@ clean_ranges (GstQueue2 * queue)
   g_slice_free_chain (GstQueue2Range, queue->ranges, next);
   queue->ranges = NULL;
   queue->current = NULL;
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+  queue->read = NULL;
+#endif
 }
 
 /* find a range that contains @offset or NULL when nothing does */
@@ -710,7 +759,11 @@ init_ranges (GstQueue2 * queue)
   /* get rid of all the current ranges */
   clean_ranges (queue);
   /* make a range for offset 0 */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+  queue->current = queue->read = add_range (queue, 0, TRUE);
+#else
   queue->current = add_range (queue, 0, TRUE);
+#endif
 }
 
 /* calculate the diff between running time on the sink and src of the queue.
@@ -754,7 +807,11 @@ apply_segment (GstQueue2 * queue, GstEvent * event, GstSegment * segment,
   if (segment->format == GST_FORMAT_BYTES) {
     if (!QUEUE_IS_USING_QUEUE (queue) && is_sink) {
       /* start is where we'll be getting from and as such writing next */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      queue->current = queue->read = add_range (queue, segment->start, TRUE);
+#else
       queue->current = add_range (queue, segment->start, TRUE);
+#endif
     }
   }
 
@@ -807,6 +864,29 @@ apply_gap (GstQueue2 * queue, GstEvent * event,
   }
 }
 
+static void
+query_downstream_bitrate (GstQueue2 * queue)
+{
+  GstQuery *query = gst_query_new_bitrate ();
+  guint downstream_bitrate = 0;
+
+  if (gst_pad_peer_query (queue->srcpad, query)) {
+    gst_query_parse_bitrate (query, &downstream_bitrate);
+    GST_DEBUG_OBJECT (queue, "Got bitrate of %u from downstream",
+        downstream_bitrate);
+  } else {
+    GST_DEBUG_OBJECT (queue, "Failed to query bitrate from downstream");
+  }
+
+  gst_query_unref (query);
+
+  GST_QUEUE2_MUTEX_LOCK (queue);
+  queue->downstream_bitrate = downstream_bitrate;
+  GST_QUEUE2_MUTEX_UNLOCK (queue);
+
+  g_object_notify (G_OBJECT (queue), "bitrate");
+}
+
 /* take a buffer and update segment, updating the time level of the queue. */
 static void
 apply_buffer (GstQueue2 * queue, GstBuffer * buffer, GstSegment * segment,
@@ -818,11 +898,24 @@ apply_buffer (GstQueue2 * queue, GstBuffer * buffer, GstSegment * segment,
   duration = GST_BUFFER_DURATION (buffer);
 
   /* If we have no duration, pick one from the bitrate if we can */
-  if (duration == GST_CLOCK_TIME_NONE && queue->use_tags_bitrate) {
-    guint bitrate =
-        is_sink ? queue->sink_tags_bitrate : queue->src_tags_bitrate;
-    if (bitrate)
-      duration = gst_util_uint64_scale (size, 8 * GST_SECOND, bitrate);
+  if (duration == GST_CLOCK_TIME_NONE) {
+    if (queue->use_tags_bitrate) {
+      guint bitrate =
+          is_sink ? queue->sink_tags_bitrate : queue->src_tags_bitrate;
+      if (bitrate)
+        duration = gst_util_uint64_scale (size, 8 * GST_SECOND, bitrate);
+    }
+    if (duration == GST_CLOCK_TIME_NONE && !is_sink && queue->use_bitrate_query) {
+      if (queue->downstream_bitrate > 0) {
+        duration =
+            gst_util_uint64_scale (size, 8 * GST_SECOND,
+            queue->downstream_bitrate);
+
+        GST_LOG_OBJECT (queue, "got bitrate %u resulting in estimated "
+            "duration %" GST_TIME_FORMAT, queue->downstream_bitrate,
+            GST_TIME_ARGS (duration));
+      }
+    }
   }
 
   /* if no timestamp is set, assume it's continuous with the previous
@@ -895,13 +988,16 @@ apply_buffer_list (GstQueue2 * queue, GstBufferList * buffer_list,
   /* if no timestamp is set, assume it's continuous with the previous time */
   bld.timestamp = segment->position;
 
+  bld.bitrate = 0;
   if (queue->use_tags_bitrate) {
     if (is_sink)
       bld.bitrate = queue->sink_tags_bitrate;
     else
       bld.bitrate = queue->src_tags_bitrate;
-  } else
-    bld.bitrate = 0;
+  }
+  if (!is_sink && bld.bitrate == 0 && queue->use_bitrate_query) {
+    bld.bitrate = queue->downstream_bitrate;
+  }
 
   gst_buffer_list_foreach (buffer_list, buffer_list_apply_time, &bld);
 
@@ -960,9 +1056,10 @@ get_buffering_level (GstQueue2 * queue, gboolean * is_buffering,
     GST_LOG_OBJECT (queue, "we are %s", queue->is_eos ? "EOS" : "NOT_LINKED");
   } else {
     GST_LOG_OBJECT (queue,
-        "Cur level bytes/time/buffers %u/%" GST_TIME_FORMAT "/%u",
-        queue->cur_level.bytes, GST_TIME_ARGS (queue->cur_level.time),
-        queue->cur_level.buffers);
+        "Cur level bytes/time/rate-time/buffers %u/%" GST_TIME_FORMAT "/%"
+        GST_TIME_FORMAT "/%u", queue->cur_level.bytes,
+        GST_TIME_ARGS (queue->cur_level.time),
+        GST_TIME_ARGS (queue->cur_level.rate_time), queue->cur_level.buffers);
 
     /* figure out the buffering level we are filled, we take the max of all formats. */
     if (!QUEUE_IS_USING_RING_BUFFER (queue)) {
@@ -1021,6 +1118,22 @@ static void
 get_buffering_stats (GstQueue2 * queue, gint percent, GstBufferingMode * mode,
     gint * avg_in, gint * avg_out, gint64 * buffering_left)
 {
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  if (queue->mode != -1) {
+    *mode = queue->mode;
+  } else {
+    if (mode) {
+      if (!QUEUE_IS_USING_QUEUE (queue)) {
+        if (QUEUE_IS_USING_RING_BUFFER (queue))
+          *mode = GST_BUFFERING_TIMESHIFT;
+        else
+          *mode = GST_BUFFERING_DOWNLOAD;
+      } else {
+        *mode = GST_BUFFERING_STREAM;
+      }
+    }
+  }
+#else
   if (mode) {
     if (!QUEUE_IS_USING_QUEUE (queue)) {
       if (QUEUE_IS_USING_RING_BUFFER (queue))
@@ -1031,6 +1144,7 @@ get_buffering_stats (GstQueue2 * queue, gint percent, GstBufferingMode * mode,
       *mode = GST_BUFFERING_STREAM;
     }
   }
+#endif
 
   if (avg_in)
     *avg_in = queue->byte_in_rate;
@@ -1107,10 +1221,23 @@ static void
 update_buffering (GstQueue2 * queue)
 {
   gint buffering_level, percent;
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+  GstQueue2Range *range;
+
+  if (queue->read)
+    range = queue->read;
+  else
+    range = queue->current;
+#endif
 
   /* Ensure the variables used to calculate buffering state are up-to-date. */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+  if (range)
+    update_cur_level (queue, range);
+#else
   if (queue->current)
     update_cur_level (queue, queue->current);
+#endif
   update_in_rates (queue, FALSE);
 
   if (!get_buffering_level (queue, NULL, &buffering_level))
@@ -1201,7 +1328,15 @@ update_in_rates (GstQueue2 * queue, gboolean force)
     queue->bytes_in = 0;
   }
 
-  if (queue->byte_in_rate > 0.0) {
+  if (queue->use_bitrate_query && queue->downstream_bitrate > 0) {
+    queue->cur_level.rate_time =
+        gst_util_uint64_scale (8 * queue->cur_level.bytes, GST_SECOND,
+        queue->downstream_bitrate);
+    GST_LOG_OBJECT (queue,
+        "got bitrate %u with byte level %u resulting in time %"
+        GST_TIME_FORMAT, queue->downstream_bitrate, queue->cur_level.bytes,
+        GST_TIME_ARGS (queue->cur_level.rate_time));
+  } else if (queue->byte_in_rate > 0.0) {
     queue->cur_level.rate_time =
         queue->cur_level.bytes / queue->byte_in_rate * GST_SECOND;
   }
@@ -1297,7 +1432,11 @@ perform_seek_to_offset (GstQueue2 * queue, guint64 offset)
      * cause data to be written to the wrong offset in the file or ring buffer.
      * We still do the add_range call to switch the current range to the
      * requested range, or create one if one doesn't exist yet. */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+    queue->current = queue->read = add_range (queue, offset, FALSE);
+#else
     queue->current = add_range (queue, offset, FALSE);
+#endif
   }
 
   return res;
@@ -1319,19 +1458,67 @@ get_seek_threshold (GstQueue2 * queue)
   return threshold;
 }
 
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+/* check the buffered data size, not to change range repeatedly.
+ * changing range cause the new http connection and it makes buffering state frequently. */
+static gboolean
+change_current_range(GstQueue2 * queue, GstQueue2Range *req_range, guint64 offset, guint length)
+{
+  guint64 curr_level = 0;
+  guint64 curr_min_level = 0;
+
+  if (queue->current->writing_pos > queue->current->reading_pos)
+    curr_level = queue->current->writing_pos - queue->current->reading_pos;
+
+  /* FIXME, find a good threshold based on the incoming rate and content bitrate. */
+  curr_min_level = MIN((queue->max_level.bytes*0.05), get_seek_threshold(queue));
+
+  GST_DEBUG_OBJECT(queue, " curr[w%"G_GUINT64_FORMAT", r%"G_GUINT64_FORMAT
+        ", d%"G_GUINT64_FORMAT", m%"G_GUINT64_FORMAT
+        "] u[%"G_GUINT64_FORMAT"][EOS:%d]",
+        queue->current->writing_pos, queue->current->reading_pos,
+        curr_level, curr_min_level,
+        queue->upstream_size, queue->is_eos);
+
+  /* FIXME, find a good threshold based on the incoming rate and content bitrate. */
+  if ((queue->is_eos) ||
+      (queue->upstream_size > 0 && queue->current->writing_pos >= queue->upstream_size) ||
+      (curr_level >= curr_min_level)) {
+    GST_DEBUG_OBJECT (queue, "Range Switching");
+    return TRUE;
+  } else {
+    GST_DEBUG_OBJECT (queue, "keep receiving data without range switching.");
+    return FALSE;
+  }
+}
+#endif
+
 /* see if there is enough data in the file to read a full buffer */
 static gboolean
 gst_queue2_have_data (GstQueue2 * queue, guint64 offset, guint length)
 {
   GstQueue2Range *range;
-
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+  gboolean need_to_seek = TRUE;
+#endif
   GST_DEBUG_OBJECT (queue, "looking for offset %" G_GUINT64_FORMAT ", len %u",
       offset, length);
 
   if ((range = find_range (queue, offset))) {
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+    queue->read = range;
+#endif
     if (queue->current != range) {
       GST_DEBUG_OBJECT (queue, "switching ranges, do seek to range position");
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      if (QUEUE_IS_USING_TEMP_FILE(queue) && !QUEUE_IS_USING_RING_BUFFER(queue))
+        need_to_seek = change_current_range(queue, range, offset, length);
+
+      if (need_to_seek == TRUE)
+        perform_seek_to_offset (queue, range->writing_pos);
+#else
       perform_seek_to_offset (queue, range->writing_pos);
+#endif
     }
 
     GST_INFO_OBJECT (queue, "cur_level.bytes %u (max %" G_GUINT64_FORMAT ")",
@@ -1355,6 +1542,11 @@ gst_queue2_have_data (GstQueue2 * queue, guint64 offset, guint length)
   } else {
     GST_INFO_OBJECT (queue, "not found in any range off %" G_GUINT64_FORMAT
         " len %u", offset, length);
+
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+    queue->read = queue->current;
+#endif
+
     /* we don't have the range, see how far away we are */
     if (!queue->is_eos && queue->current) {
       guint64 threshold = get_seek_threshold (queue);
@@ -1478,15 +1670,24 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length,
         guint64 level;
 
         /* calculate how far away the offset is */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+        if (queue->read->writing_pos > rpos)
+          level = queue->read->writing_pos - rpos;
+#else
         if (queue->current->writing_pos > rpos)
           level = queue->current->writing_pos - rpos;
+#endif
         else
           level = 0;
 
         GST_DEBUG_OBJECT (queue,
             "reading %" G_GUINT64_FORMAT ", writing %" G_GUINT64_FORMAT
             ", level %" G_GUINT64_FORMAT ", max %" G_GUINT64_FORMAT,
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+            rpos, queue->read->writing_pos, level, max_size);
+#else
             rpos, queue->current->writing_pos, level, max_size);
+#endif
 
         if (level >= max_size) {
           /* we don't have the data but if we have a ring buffer that is full, we
@@ -1511,10 +1712,17 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length,
 
       if (read_length == 0) {
         if (QUEUE_IS_USING_RING_BUFFER (queue)) {
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+          GST_DEBUG_OBJECT (queue,
+              "update current position [%" G_GUINT64_FORMAT "-%"
+              G_GUINT64_FORMAT "]", rpos, queue->read->max_reading_pos);
+          update_cur_pos (queue, queue->read, rpos);
+#else
           GST_DEBUG_OBJECT (queue,
               "update current position [%" G_GUINT64_FORMAT "-%"
               G_GUINT64_FORMAT "]", rpos, queue->current->max_reading_pos);
           update_cur_pos (queue, queue->current, rpos);
+#endif
           GST_QUEUE2_SIGNAL_DEL (queue);
         }
 
@@ -1531,13 +1739,22 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length,
     }
 
     /* set range reading_pos to actual reading position for this read */
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+    queue->read->reading_pos = rpos;
+#else
     queue->current->reading_pos = rpos;
+#endif
 
     /* configure how much and from where to read */
     if (QUEUE_IS_USING_RING_BUFFER (queue)) {
       file_offset =
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+          (queue->read->rb_offset + (rpos -
+              queue->read->offset)) % rb_size;
+#else
           (queue->current->rb_offset + (rpos -
               queue->current->offset)) % rb_size;
+#endif
       if (file_offset + read_length > rb_size) {
         block_length = rb_size - file_offset;
       } else {
@@ -1567,8 +1784,13 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length,
       block_length = read_length;
       remaining -= read_return;
 
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      rpos = (queue->read->reading_pos += read_return);
+      update_cur_pos (queue, queue->read, queue->read->reading_pos);
+#else
       rpos = (queue->current->reading_pos += read_return);
       update_cur_pos (queue, queue->current, queue->current->reading_pos);
+#endif
     }
     GST_QUEUE2_SIGNAL_DEL (queue);
     GST_DEBUG_OBJECT (queue, "%u bytes left to read", remaining);
@@ -1636,7 +1858,11 @@ gst_queue2_read_item_from_file (GstQueue2 * queue)
     GstBuffer *buffer = NULL;
     guint64 reading_pos;
 
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+    reading_pos = queue->read->reading_pos;
+#else
     reading_pos = queue->current->reading_pos;
+#endif
 
     ret =
         gst_queue2_create_read (queue, reading_pos, DEFAULT_BUFFER_SIZE,
@@ -1920,8 +2146,10 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
         guint64 range_data_start, range_data_end;
         GstQueue2Range *range_to_destroy = NULL;
 
+#ifndef TIZEN_FEATURE_QUEUE2_MODIFICATION
         if (range == queue->current)
           goto next_range;
+#endif
 
         range_data_start = range->rb_offset;
         range_data_end = range->rb_writing_pos;
@@ -1945,7 +2173,11 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
             goto next_range;
 
           if (new_writing_pos > range_data_start) {
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+            if (new_writing_pos >= range_data_end && range != queue->current) {
+#else
             if (new_writing_pos >= range_data_end) {
+#endif
               GST_DEBUG_OBJECT (queue,
                   "Removing range: offset %" G_GUINT64_FORMAT ", wpos %"
                   G_GUINT64_FORMAT, range->offset, range->writing_pos);
@@ -1970,7 +2202,12 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
           if (new_wpos_virt <= range_data_start)
             goto next_range;
 
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+          if (new_wpos_virt > rb_size && new_writing_pos >= range_data_end
+            && range != queue->current) {
+#else
           if (new_wpos_virt > rb_size && new_writing_pos >= range_data_end) {
+#endif
             GST_DEBUG_OBJECT (queue,
                 "Removing range: offset %" G_GUINT64_FORMAT ", wpos %"
                 G_GUINT64_FORMAT, range->offset, range->writing_pos);
@@ -2097,9 +2334,20 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
       queue->current->rb_writing_pos = writing_pos = new_writing_pos;
     } else {
       queue->current->writing_pos = writing_pos = new_writing_pos;
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      if (do_seek) {
+        if (queue->upstream_size == 0 || new_writing_pos < queue->upstream_size)
+          perform_seek_to_offset (queue, new_writing_pos);
+        else
+          queue->is_eos = TRUE;
+      }
+#endif
     }
+
+#ifndef TIZEN_FEATURE_QUEUE2_MODIFICATION
     if (do_seek)
       perform_seek_to_offset (queue, new_writing_pos);
+#endif
 
     update_cur_level (queue, queue->current);
 
@@ -2531,6 +2779,7 @@ gst_queue2_handle_sink_event (GstPad * pad, GstObject * parent,
 
         gst_event_unref (event);
       }
+      g_object_notify (G_OBJECT (queue), "bitrate");
       break;
     }
     case GST_EVENT_TAG:{
@@ -2545,12 +2794,14 @@ gst_queue2_handle_sink_event (GstPad * pad, GstObject * parent,
           queue->sink_tags_bitrate = bitrate;
           GST_QUEUE2_MUTEX_UNLOCK (queue);
           GST_LOG_OBJECT (queue, "Sink pad bitrate from tags now %u", bitrate);
+          g_object_notify (G_OBJECT (queue), "bitrate");
         }
       }
       /* Fall-through */
     }
     default:
       if (GST_EVENT_IS_SERIALIZED (event)) {
+        gboolean bitrate_changed = TRUE;
         /* serialized events go in the queue */
 
         /* STREAM_START and SEGMENT reset the EOS status of a
@@ -2600,6 +2851,7 @@ gst_queue2_handle_sink_event (GstPad * pad, GstObject * parent,
                 queue->seeking = FALSE;
                 queue->src_tags_bitrate = queue->sink_tags_bitrate = 0;
               }
+              bitrate_changed = TRUE;
 
               break;
             default:
@@ -2610,6 +2862,8 @@ gst_queue2_handle_sink_event (GstPad * pad, GstObject * parent,
         gst_queue2_locked_enqueue (queue, event, GST_QUEUE2_ITEM_TYPE_EVENT);
         GST_QUEUE2_MUTEX_UNLOCK (queue);
         gst_queue2_post_buffering (queue);
+        if (bitrate_changed)
+          g_object_notify (G_OBJECT (queue), "bitrate");
       } else {
         /* non-serialized events are passed downstream. */
         ret = gst_pad_push_event (queue->srcpad, event);
@@ -2660,7 +2914,8 @@ gst_queue2_handle_sink_query (GstPad * pad, GstObject * parent,
   switch (GST_QUERY_TYPE (query)) {
     default:
       if (GST_QUERY_IS_SERIALIZED (query)) {
-        GST_CAT_LOG_OBJECT (queue_dataflow, queue, "received query %p", query);
+        GST_CAT_LOG_OBJECT (queue_dataflow, queue,
+            "received query %" GST_PTR_FORMAT, query);
         /* serialized events go in the queue. We need to be certain that we
          * don't cause deadlocks waiting for the query return value. We check if
          * the queue is empty (nothing is blocking downstream and the query can
@@ -2974,6 +3229,7 @@ next:
           queue->src_tags_bitrate = bitrate;
           GST_QUEUE2_MUTEX_UNLOCK (queue);
           GST_LOG_OBJECT (queue, "src pad bitrate from tags now %u", bitrate);
+          g_object_notify (G_OBJECT (queue), "bitrate");
         }
       }
     }
@@ -3042,7 +3298,11 @@ static void
 gst_queue2_loop (GstPad * pad)
 {
   GstQueue2 *queue;
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  GstFlowReturn ret = GST_FLOW_OK;
+#else
   GstFlowReturn ret;
+#endif
 
   queue = GST_QUEUE2 (GST_PAD_PARENT (pad));
 
@@ -3069,7 +3329,14 @@ gst_queue2_loop (GstPad * pad)
     if (started)
       g_timer_continue (queue->out_timer);
   }
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+  /* if buffering mode is GST_BUFFERING_LIVE, it is rtsp streaming */
+  if (!((queue->mode == GST_BUFFERING_LIVE) && queue->is_buffering)) {
+    ret = gst_queue2_push_one (queue);
+  }
+#else
   ret = gst_queue2_push_one (queue);
+#endif
   queue->srcresult = ret;
   queue->sinkresult = ret;
   if (ret != GST_FLOW_OK)
@@ -3167,9 +3434,13 @@ gst_queue2_handle_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
           gst_pad_start_task (pad, (GstTaskFunction) gst_queue2_loop, pad,
               NULL);
         }
+
       }
       GST_QUEUE2_MUTEX_UNLOCK (queue);
 
+      /* force a new bitrate query to be performed */
+      query_downstream_bitrate (queue);
+
       res = gst_pad_push_event (queue->sinkpad, event);
       break;
     default:
@@ -3325,15 +3596,25 @@ gst_queue2_handle_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
                 range_stop = 0;
                 break;
               }
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+              range_start =
+                  gst_util_uint64_scale (GST_FORMAT_PERCENT_MAX,
+                  queued_ranges->reading_pos, duration);
+#else
               range_start =
                   gst_util_uint64_scale (GST_FORMAT_PERCENT_MAX,
                   queued_ranges->offset, duration);
+#endif
               range_stop =
                   gst_util_uint64_scale (GST_FORMAT_PERCENT_MAX,
                   queued_ranges->writing_pos, duration);
               break;
             case GST_FORMAT_BYTES:
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+              range_start = queued_ranges->reading_pos;
+#else
               range_start = queued_ranges->offset;
+#endif
               range_stop = queued_ranges->writing_pos;
               break;
             default:
@@ -3358,12 +3639,25 @@ gst_queue2_handle_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
     {
       gboolean pull_mode;
       GstSchedulingFlags flags = 0;
-
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      if ((!QUEUE_IS_USING_QUEUE (queue)) && !gst_pad_peer_query (queue->sinkpad, query))
+#else
       if (!gst_pad_peer_query (queue->sinkpad, query))
+#endif
         goto peer_failed;
 
       gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
 
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      if (!(flags & GST_SCHEDULING_FLAG_SEEKABLE)) {
+        GST_DEBUG_OBJECT(queue, "peer can support only push mode");
+        gst_query_set_scheduling (query, flags, 0, -1, 0);
+        gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH);
+        break;
+      }
+#endif
+      GST_DEBUG_OBJECT(queue, "peer can support pull mode");
+
       /* we can operate in pull mode when we are using a tempfile */
       pull_mode = !QUEUE_IS_USING_QUEUE (queue);
 
@@ -3670,8 +3964,14 @@ gst_queue2_change_state (GstElement * element, GstStateChange transition)
       queue->starting_segment = NULL;
       gst_event_replace (&queue->stream_start_event, NULL);
       GST_QUEUE2_MUTEX_UNLOCK (queue);
+      query_downstream_bitrate (queue);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+#ifdef TIZEN_FEATURE_QUEUE2_MODIFICATION
+      GST_QUEUE2_MUTEX_LOCK (queue);
+      queue->is_buffering = FALSE;
+      GST_QUEUE2_MUTEX_UNLOCK (queue);
+#endif
       break;
     default:
       break;
@@ -3832,6 +4132,14 @@ gst_queue2_set_property (GObject * object,
     case PROP_RING_BUFFER_MAX_SIZE:
       queue->ring_buffer_max_size = g_value_get_uint64 (value);
       break;
+    case PROP_USE_BITRATE_QUERY:
+      queue->use_bitrate_query = g_value_get_boolean (value);
+      break;
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+    case PROP_BUFFER_MODE:
+      queue->mode = g_value_get_enum (value);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3916,6 +4224,28 @@ gst_queue2_get_property (GObject * object,
       g_value_set_int64 (value, (gint64) in_rate);
       break;
     }
+    case PROP_USE_BITRATE_QUERY:
+      g_value_set_boolean (value, queue->use_bitrate_query);
+      break;
+    case PROP_BITRATE:{
+      guint64 bitrate = 0;
+      if (bitrate == 0 && queue->use_tags_bitrate) {
+        if (queue->sink_tags_bitrate > 0)
+          bitrate = queue->sink_tags_bitrate;
+        else if (queue->src_tags_bitrate)
+          bitrate = queue->src_tags_bitrate;
+      }
+      if (bitrate == 0 && queue->use_bitrate_query) {
+        bitrate = queue->downstream_bitrate;
+      }
+      g_value_set_uint64 (value, (guint64) bitrate);
+      break;
+    }
+#ifdef TIZEN_FEATURE_RTSPSRC_MODIFICATION
+    case PROP_BUFFER_MODE:
+      g_value_set_enum (value, queue->mode);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;