]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/mathematics.c
Merge commit 'cdfe45ad371b7a8e6135b6c063b6b2a93152cb3a'
[ffmpeg] / libavutil / mathematics.c
index c9b24afeacde78bbeec76e17264221d158cfe920..252794e46005246b08f27c734e0eaa210333e57b 100644 (file)
@@ -1,20 +1,20 @@
 /*
- * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2005-2012 Michael Niedermayer <michaelni@gmx.at>
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -27,6 +27,8 @@
 #include <limits.h>
 
 #include "mathematics.h"
+#include "libavutil/common.h"
+#include "avassert.h"
 #include "version.h"
 
 int64_t av_gcd(int64_t a, int64_t b)
@@ -40,10 +42,19 @@ int64_t av_gcd(int64_t a, int64_t b)
 int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
 {
     int64_t r = 0;
+    av_assert2(c > 0);
+    av_assert2(b >=0);
+    av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4);
 
-    if (c <= 0 || b < 0 || rnd == 4 || rnd > 5)
+    if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4))
         return INT64_MIN;
 
+    if (rnd & AV_ROUND_PASS_MINMAX) {
+        if (a == INT64_MIN || a == INT64_MAX)
+            return a;
+        rnd -= AV_ROUND_PASS_MINMAX;
+    }
+
     if (a < 0 && a != INT64_MIN)
         return -av_rescale_rnd(-a, b, c, rnd ^ ((rnd >> 1) & 1));
 
@@ -114,6 +125,8 @@ int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
 {
     int64_t a = tb_a.num * (int64_t)tb_b.den;
     int64_t b = tb_b.num * (int64_t)tb_a.den;
+    if ((FFABS(ts_a)|a|FFABS(ts_b)|b) <= INT_MAX)
+        return (ts_a*a > ts_b*b) - (ts_a*a < ts_b*b);
     if (av_rescale_rnd(ts_a, a, b, AV_ROUND_DOWN) < ts_b)
         return -1;
     if (av_rescale_rnd(ts_b, b, a, AV_ROUND_DOWN) < ts_a)
@@ -128,3 +141,48 @@ int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod)
         c -= mod;
     return c;
 }
+
+int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts,  AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
+    int64_t a, b, this;
+
+    av_assert0(in_ts != AV_NOPTS_VALUE);
+    av_assert0(duration >= 0);
+
+    if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) {
+simple_round:
+        *last = av_rescale_q(in_ts, in_tb, fs_tb) + duration;
+        return av_rescale_q(in_ts, in_tb, out_tb);
+    }
+
+    a =  av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN)   >>1;
+    b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP  )+1)>>1;
+    if (*last < 2*a - b || *last > 2*b - a)
+        goto simple_round;
+
+    this = av_clip64(*last, a, b);
+    *last = this + duration;
+
+    return av_rescale_q(this, fs_tb, out_tb);
+}
+
+int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc)
+{
+    int64_t m, d;
+
+    if (inc != 1)
+        inc_tb = av_mul_q(inc_tb, (AVRational) {inc, 1});
+
+    m = inc_tb.num * (int64_t)ts_tb.den;
+    d = inc_tb.den * (int64_t)ts_tb.num;
+
+    if (m % d == 0)
+        return ts + m / d;
+    if (m < d)
+        return ts;
+
+    {
+        int64_t old = av_rescale_q(ts, ts_tb, inc_tb);
+        int64_t old_ts = av_rescale_q(old, inc_tb, ts_tb);
+        return av_rescale_q(old + 1, inc_tb, ts_tb) + (ts - old_ts);
+    }
+}