videorate: handle invalid timestamps better
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 30 Apr 2009 14:37:38 +0000 (16:37 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 12 May 2009 08:47:17 +0000 (10:47 +0200)
Handle buffers with -1 timestamps better by keeping track of the en time of the
previous buffer and assuming the -1 timestamp buffer goes right after the
previous one.

when we have two buffers that are equally good, output the oldest buffer once to
minimize latency.

don't try to calculate latency when the input framerate is unknown.

gst/videorate/gstvideorate.c
gst/videorate/gstvideorate.h

index 7de2bb9..1a8769f 100644 (file)
@@ -268,6 +268,7 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
     videorate->from_rate_denominator = rate_denominator;
     otherpad = videorate->srcpad;
   }
+
   /* now try to find something for the peer */
   opeer = gst_pad_get_peer (otherpad);
   if (opeer) {
@@ -358,6 +359,7 @@ gst_video_rate_reset (GstVideoRate * videorate)
   videorate->drop = 0;
   videorate->dup = 0;
   videorate->next_ts = GST_CLOCK_TIME_NONE;
+  videorate->last_ts = GST_CLOCK_TIME_NONE;
   videorate->discont = TRUE;
   gst_video_rate_swap_prev (videorate, NULL, 0);
 
@@ -584,11 +586,17 @@ gst_video_rate_query (GstPad * pad, GstQuery * query)
               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
 
-          /* add latency. We don't really know since we hold on to the frames
-           * until we get a next frame, which can be anything. We assume
-           * however that this will take from_rate time. */
-          latency = gst_util_uint64_scale (GST_SECOND,
-              videorate->from_rate_denominator, videorate->from_rate_numerator);
+          if (videorate->from_rate_numerator != 0) {
+            /* add latency. We don't really know since we hold on to the frames
+             * until we get a next frame, which can be anything. We assume
+             * however that this will take from_rate time. */
+            latency = gst_util_uint64_scale (GST_SECOND,
+                videorate->from_rate_denominator,
+                videorate->from_rate_numerator);
+          } else {
+            /* no input framerate, we don't know */
+            latency = 0;
+          }
 
           GST_DEBUG_OBJECT (videorate, "Our latency: %"
               GST_TIME_FORMAT, GST_TIME_ARGS (latency));
@@ -621,7 +629,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstVideoRate *videorate;
   GstFlowReturn res = GST_FLOW_OK;
-  GstClockTime intime, in_ts;
+  GstClockTime intime, in_ts, in_dur;
 
   videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
 
@@ -631,9 +639,19 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
     goto not_negotiated;
 
   in_ts = GST_BUFFER_TIMESTAMP (buffer);
+  in_dur = GST_BUFFER_DURATION (buffer);
+
+  if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE)) {
+    in_ts = videorate->last_ts;
+    if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE))
+      goto invalid_buffer;
+  }
 
-  if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE))
-    goto invalid_buffer;
+  /* get the time of the next expected buffer timestamp, we use this when the
+   * next buffer has -1 as a timestamp */
+  videorate->last_ts = in_ts;
+  if (in_dur != GST_CLOCK_TIME_NONE)
+    videorate->last_ts += in_dur;
 
   GST_DEBUG_OBJECT (videorate, "got buffer with timestamp %" GST_TIME_FORMAT,
       GST_TIME_ARGS (in_ts));
@@ -698,7 +716,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
           GST_TIME_ARGS (videorate->next_ts));
 
       /* output first one when its the best */
-      if (diff1 < diff2) {
+      if (diff1 <= diff2) {
         count++;
 
         /* on error the _flush function posted a warning already */
@@ -707,7 +725,8 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
           goto done;
         }
       }
-      /* continue while the first one was the best */
+      /* continue while the first one was the best, if they were equal avoid
+       * going into an infinite loop */
     }
     while (diff1 < diff2);
 
@@ -820,6 +839,7 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       videorate->discont = TRUE;
+      videorate->last_ts = -1;
       break;
     default:
       break;
index fe7feb6..2a2d7e3 100644 (file)
@@ -57,6 +57,7 @@ struct _GstVideoRate
   guint64 prev_ts;              /* Previous buffer timestamp */
   guint64 segment_out;          /* in-segment counting */
   gboolean discont;
+  guint64 last_ts;              /* Timestamp of last input buffer */
 
   /* segment handling */
   GstSegment segment;