summaryrefslogtreecommitdiff
path: root/libavcodec/utils.c
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2003-10-20 22:33:53 +0000
committerMichael Niedermayer <michaelni@gmx.at>2003-10-20 22:33:53 +0000
commit5ed9f2e5aaa922b423e87a1b812ca5489238d08e (patch)
tree6cba9ce51d8310ac6ded1b8b107d341129390d8b /libavcodec/utils.c
parent1c0dcc391a302068199385ecc158aae52b5d3e69 (diff)
use continued fractions to approximate a fraction if its numerator or denominator is too large
Originally committed as revision 2405 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/utils.c')
-rw-r--r--libavcodec/utils.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index f9ed4f5ab6..34051ad3a4 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -684,7 +684,7 @@ char av_get_pict_type_char(int pict_type){
int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max){
int exact=1, sign=0;
- int64_t gcd, larger;
+ int64_t gcd;
assert(den != 0);
@@ -698,22 +698,34 @@ int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max)
sign= 1;
}
- for(;;){ //note is executed 1 or 2 times
- gcd = ff_gcd(nom, den);
- nom /= gcd;
- den /= gcd;
+ gcd = ff_gcd(nom, den);
+ nom /= gcd;
+ den /= gcd;
- larger= FFMAX(nom, den);
-
- if(larger > max){
- int64_t div= (larger + max - 1) / max;
- nom = (nom + div/2)/div;
- den = (den + div/2)/div;
- exact=0;
- }else
- break;
+ if(nom > max || den > max){
+ AVRational a0={0,1}, a1={1,0};
+ exact=0;
+
+ for(;;){
+ int64_t x= nom / den;
+ int64_t a2n= x*a1.num + a0.num;
+ int64_t a2d= x*a1.den + a0.den;
+
+ if(a2n > max || a2d > max) break;
+
+ nom %= den;
+
+ a0= a1;
+ a1= (AVRational){a2n, a2d};
+ if(nom==0) break;
+ x= nom; nom=den; den=x;
+ }
+ nom= a1.num;
+ den= a1.den;
}
+ assert(ff_gcd(nom, den) == 1);
+
if(sign) nom= -nom;
*dst_nom = nom;