videorate: Fix behaviour for frame rate cap changes
authorRobert Swain <robert.swain@collabora.co.uk>
Thu, 6 Jan 2011 12:08:53 +0000 (13:08 +0100)
committerRobert Swain <robert.swain@collabora.co.uk>
Thu, 6 Jan 2011 12:12:05 +0000 (13:12 +0100)
The outgoing buffer timestamp is calculated by scaling an output buffer
count by the src pad frame rate caps. If these caps change, we need to
reset the count and work from a new base timestamp. The new output
buffer timestamp is then the count scaled by the new caps values added
onto the base timestamp.

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

index 827f0e9..a0642c2 100644 (file)
@@ -290,6 +290,16 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
     goto no_framerate;
 
   if (pad == videorate->srcpad) {
+    /* out_frame_count is scaled by the frame rate caps when calculating next_ts.
+     * when the frame rate caps change, we must update base_ts and reset
+     * out_frame_count */
+    if (videorate->to_rate_numerator) {
+      videorate->base_ts +=
+          gst_util_uint64_scale (videorate->out_frame_count,
+          videorate->to_rate_denominator * GST_SECOND,
+          videorate->to_rate_numerator);
+    }
+    videorate->out_frame_count = 0;
     videorate->to_rate_numerator = rate_numerator;
     videorate->to_rate_denominator = rate_denominator;
     otherpad = videorate->sinkpad;
@@ -394,7 +404,8 @@ gst_video_rate_reset (GstVideoRate * videorate)
 
   videorate->in = 0;
   videorate->out = 0;
-  videorate->segment_out = 0;
+  videorate->base_ts = 0;
+  videorate->out_frame_count = 0;
   videorate->drop = 0;
   videorate->dup = 0;
   videorate->next_ts = GST_CLOCK_TIME_NONE;
@@ -473,11 +484,12 @@ gst_video_rate_flush_prev (GstVideoRate * videorate, gboolean duplicate)
   push_ts = videorate->next_ts;
 
   videorate->out++;
-  videorate->segment_out++;
+  videorate->out_frame_count++;
   if (videorate->to_rate_numerator) {
     /* interpolate next expected timestamp in the segment */
-    videorate->next_ts = videorate->segment.accum + videorate->segment.start +
-        gst_util_uint64_scale (videorate->segment_out,
+    videorate->next_ts =
+        videorate->segment.accum + videorate->segment.start +
+        videorate->base_ts + gst_util_uint64_scale (videorate->out_frame_count,
         videorate->to_rate_denominator * GST_SECOND,
         videorate->to_rate_numerator);
     GST_BUFFER_DURATION (outbuf) = videorate->next_ts - push_ts;
@@ -587,7 +599,8 @@ gst_video_rate_event (GstPad * pad, GstEvent * event)
             gst_video_rate_notify_drop (videorate);
         }
         /* clean up for the new one; _chain will resume from the new start */
-        videorate->segment_out = 0;
+        videorate->base_ts = 0;
+        videorate->out_frame_count = 0;
         gst_video_rate_swap_prev (videorate, NULL, 0);
         videorate->next_ts = GST_CLOCK_TIME_NONE;
       }
@@ -783,7 +796,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
        * timestamp in the segment */
       if (videorate->skip_to_first) {
         videorate->next_ts = in_ts;
-        videorate->segment_out = gst_util_uint64_scale (in_ts,
+        videorate->out_frame_count = gst_util_uint64_scale (in_ts,
             videorate->to_rate_numerator,
             videorate->to_rate_denominator * GST_SECOND) -
             (videorate->segment.accum + videorate->segment.start);
index 4d6c061..23e2056 100644 (file)
@@ -55,7 +55,11 @@ struct _GstVideoRate
   guint64 next_ts;              /* Timestamp of next buffer to output */
   GstBuffer *prevbuf;
   guint64 prev_ts;              /* Previous buffer timestamp */
-  guint64 segment_out;          /* in-segment counting */
+  guint64 out_frame_count;      /* number of frames output since the beginning
+                                 * of the segment or the last frame rate caps
+                                 * change, whichever was later */
+  guint64 base_ts;              /* used in next_ts calculation after a
+                                 * frame rate caps change */
   gboolean discont;
   guint64 last_ts;              /* Timestamp of last input buffer */