[FFmpeg-cvslog] af_asyncts: fix compensation and PTS monotonicity

Jindřich Makovička git at videolan.org
Sat Mar 23 12:22:22 CET 2013


ffmpeg | branch: master | Jindřich Makovička <makovick at gmail.com> | Sat Mar  9 10:08:09 2013 +0100| [20a8ee3061e6d777600c13db731bee3c25878991] | committer: Anton Khirnov

af_asyncts: fix compensation and PTS monotonicity

This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.

Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.

To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.

Finally, one more monotonicity check is added.

The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.

Signed-off-by: Jindřich Makovička <makovick at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=20a8ee3061e6d777600c13db731bee3c25878991
---

 libavfilter/af_asyncts.c |   31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c
index 2e651ff..006839c 100644
--- a/libavfilter/af_asyncts.c
+++ b/libavfilter/af_asyncts.c
@@ -35,6 +35,7 @@ typedef struct ASyncContext {
     int min_delta;          ///< pad/trim min threshold in samples
     int first_frame;        ///< 1 until filter_frame() has processed at least 1 frame with a pts != AV_NOPTS_VALUE
     int64_t first_pts;      ///< user-specified first expected pts, in samples
+    int comp;               ///< current resample compensation
 
     /* options */
     int resample;
@@ -194,6 +195,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
                   av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
     int out_size, ret;
     int64_t delta;
+    int64_t new_pts;
 
     /* buffer data until we get the next timestamp */
     if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) {
@@ -220,10 +222,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
         out_size = av_clipl_int32((int64_t)out_size + delta);
     } else {
         if (s->resample) {
-            int comp = av_clip(delta, -s->max_comp, s->max_comp);
-            av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
-            avresample_set_compensation(s->avr, comp, inlink->sample_rate);
+            // adjust the compensation if delta is non-zero
+            int delay = get_delay(s);
+            int comp = s->comp + av_clip(delta * inlink->sample_rate / delay,
+                                         -s->max_comp, s->max_comp);
+            if (comp != s->comp) {
+                av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
+                if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) {
+                    s->comp = comp;
+                }
+            }
         }
+        // adjust PTS to avoid monotonicity errors with input PTS jitter
+        pts -= delta;
         delta = 0;
     }
 
@@ -268,9 +279,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     /* drain any remaining buffered data */
     avresample_read(s->avr, NULL, avresample_available(s->avr));
 
-    s->pts = pts - avresample_get_delay(s->avr);
-    ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
-                             buf->linesize[0], buf->nb_samples);
+    new_pts = pts - avresample_get_delay(s->avr);
+    /* check for s->pts monotonicity */
+    if (new_pts > s->pts) {
+        s->pts = new_pts;
+        ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
+                                 buf->linesize[0], buf->nb_samples);
+    } else {
+        av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
+               "whole buffer.\n");
+        ret = 0;
+    }
 
     s->first_frame = 0;
 fail:



More information about the ffmpeg-cvslog mailing list