changeset 1126:77ccf7fe3bd0 libavcodec

per context frame_rate_base, this should finally fix frame_rate related av sync issues
author michaelni
date Wed, 12 Mar 2003 15:16:19 +0000
parents 0980ae063f4e
children 7bde81d2f2c5
files apiexample.c avcodec.h common.c common.h dv.c h263.c mpeg12.c mpeg12data.h mpegvideo.c mpegvideo.h msmpeg4.c ratecontrol.c utils.c wmv2.c
diffstat 14 files changed, 152 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/apiexample.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/apiexample.c	Wed Mar 12 15:16:19 2003 +0000
@@ -192,7 +192,8 @@
     c->width = 352;  
     c->height = 288;
     /* frames per second */
-    c->frame_rate = 25 * FRAME_RATE_BASE;  
+    c->frame_rate = 25;  
+    c->frame_rate_base= 1;
     c->gop_size = 10; /* emit one intra frame every ten frames */
 
     /* open it */
--- a/avcodec.h	Tue Mar 11 12:09:13 2003 +0000
+++ b/avcodec.h	Wed Mar 12 15:16:19 2003 +0000
@@ -186,8 +186,6 @@
 #define CODEC_CAP_PARSE_ONLY      0x0004
 #define CODEC_CAP_TRUNCATED       0x0008
 
-#define FRAME_RATE_BASE 10010
-
 #define FF_COMMON_FRAME \
     uint8_t *data[4];\
     int linesize[4];\
@@ -321,6 +319,7 @@
     FF_COMMON_FRAME
 } AVFrame;
 
+#define DEFAULT_FRAME_RATE_BASE 1001000
 
 /**
  * main external api structure.
@@ -375,13 +374,21 @@
     
     /* video only */
     /**
-     * frames per sec multiplied by FRAME_RATE_BASE.
+     * frames per sec multiplied by frame_rate_base.
      * for variable fps this is the precission, so if the timestamps 
-     * can be specified in msec precssion then this is 1000*FRAME_RATE_BASE
+     * can be specified in msec precssion then this is 1000*frame_rate_base
      * - encoding: MUST be set by user
      * - decoding: set by lavc. 0 or the frame_rate if available
      */
     int frame_rate;
+    
+    /**
+     * frame_rate_base.
+     * for variable fps this is 1
+     * - encoding: set by user.
+     * - decoding: set by lavc.
+     */
+    int frame_rate_base;
 
     /**
      * width / height.
@@ -1258,6 +1265,20 @@
 
 void avcodec_flush_buffers(AVCodecContext *avctx);
 
+/* misc usefull functions */
+/**
+ * reduce a fraction.
+ * this is usefull for framerate calculations
+ * @param max the maximum allowed for dst_nom & dst_den
+ * @return 1 if exact, 0 otherwise
+ */
+int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max);
+
+/**
+ * rescale a 64bit integer.
+ * a simple a*b/c isnt possible as it can overflow
+ */
+int64_t av_rescale(int64_t a, int b, int c);
 
 
 /**
--- a/common.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/common.c	Wed Mar 12 15:16:19 2003 +0000
@@ -341,7 +341,7 @@
     av_free(vlc->table);
 }
 
-int ff_gcd(int a, int b){
+int64_t ff_gcd(int64_t a, int64_t b){
     if(b) return ff_gcd(b, a%b);
     else  return a;
 }
--- a/common.h	Tue Mar 11 12:09:13 2003 +0000
+++ b/common.h	Wed Mar 12 15:16:19 2003 +0000
@@ -876,7 +876,7 @@
 /* math */
 extern const uint8_t ff_sqrt_tab[128];
 
-int ff_gcd(int a, int b);
+int64_t ff_gcd(int64_t a, int64_t b);
 
 static inline int ff_sqrt(int a)
 {
--- a/dv.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/dv.c	Wed Mar 12 15:16:19 2003 +0000
@@ -537,16 +537,17 @@
     /* init size */
     width = 720;
     if (dsf) {
-        avctx->frame_rate = 25 * FRAME_RATE_BASE;
+        avctx->frame_rate = 25;
         packet_size = PAL_FRAME_SIZE;
         height = 576;
         nb_dif_segs = 12;
     } else {
-        avctx->frame_rate = 30 * FRAME_RATE_BASE;
+        avctx->frame_rate = 30;
         packet_size = NTSC_FRAME_SIZE;
         height = 480;
         nb_dif_segs = 10;
     }
+    avctx->frame_rate_base= 1;
     /* NOTE: we only accept several full frames */
     if (buf_size < packet_size)
         return -1;
--- a/h263.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/h263.c	Wed Mar 12 15:16:19 2003 +0000
@@ -164,8 +164,8 @@
     s->gob_number = 0;
 
     put_bits(&s->pb, 22, 0x20); /* PSC */
-    put_bits(&s->pb, 8, (((int64_t)s->picture_number * 30 * FRAME_RATE_BASE) / 
-                         s->frame_rate) & 0xff);
+    put_bits(&s->pb, 8, (((int64_t)s->picture_number * 30 * s->avctx->frame_rate_base) / 
+                         s->avctx->frame_rate) & 0xff);
 
     put_bits(&s->pb, 1, 1);	/* marker */
     put_bits(&s->pb, 1, 0);	/* h263 id */
@@ -1587,16 +1587,16 @@
     int time_div, time_mod;
 
     if(s->pict_type==I_TYPE){ //we will encode a vol header
-        s->time_increment_resolution= s->frame_rate/ff_gcd(s->frame_rate, FRAME_RATE_BASE);
-        if(s->time_increment_resolution>=256*256) s->time_increment_resolution= 256*128;
-
+        int dummy;
+        av_reduce(&s->time_increment_resolution, &dummy, s->avctx->frame_rate, s->avctx->frame_rate_base, (1<<16)-1);
+        
         s->time_increment_bits = av_log2(s->time_increment_resolution - 1) + 1;
     }
     
     if(s->current_picture.pts)
         s->time= (s->current_picture.pts*s->time_increment_resolution + 500*1000)/(1000*1000);
     else
-        s->time= picture_number*(int64_t)FRAME_RATE_BASE*s->time_increment_resolution/s->frame_rate;
+        s->time= av_rescale(picture_number*(int64_t)s->avctx->frame_rate_base, s->time_increment_resolution, s->avctx->frame_rate);
     time_div= s->time/s->time_increment_resolution;
     time_mod= s->time%s->time_increment_resolution;
 
--- a/mpeg12.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/mpeg12.c	Wed Mar 12 15:16:19 2003 +0000
@@ -203,8 +203,10 @@
                 int i, dmin, d;
                 s->frame_rate_index = 0;
                 dmin = 0x7fffffff;
-                for(i=1;i<9;i++) {
-                    d = abs(s->frame_rate - frame_rate_tab[i]);
+                for(i=1;i<14;i++) {
+                    if(s->avctx->strict_std_compliance >= 0 && i>=9) break;
+                     
+                    d = abs(MPEG1_FRAME_RATE_BASE*(int64_t)s->avctx->frame_rate/s->avctx->frame_rate_base - frame_rate_tab[i]);
                     if (d < dmin) {
                         dmin = d;
                         s->frame_rate_index = i;
@@ -248,22 +250,22 @@
             /* time code : we must convert from the real frame rate to a
                fake mpeg frame rate in case of low frame rate */
             fps = frame_rate_tab[s->frame_rate_index];
-            time_code = (int64_t)s->fake_picture_number * FRAME_RATE_BASE;
+            time_code = (int64_t)s->fake_picture_number * MPEG1_FRAME_RATE_BASE;
             s->gop_picture_number = s->fake_picture_number;
             put_bits(&s->pb, 5, (uint32_t)((time_code / (fps * 3600)) % 24));
             put_bits(&s->pb, 6, (uint32_t)((time_code / (fps * 60)) % 60));
             put_bits(&s->pb, 1, 1);
             put_bits(&s->pb, 6, (uint32_t)((time_code / fps) % 60));
-            put_bits(&s->pb, 6, (uint32_t)((time_code % fps) / FRAME_RATE_BASE));
+            put_bits(&s->pb, 6, (uint32_t)((time_code % fps) / MPEG1_FRAME_RATE_BASE));
             put_bits(&s->pb, 1, 1); /* closed gop */
             put_bits(&s->pb, 1, 0); /* broken link */
         }
 
-        if (s->frame_rate < (24 * FRAME_RATE_BASE) && s->picture_number > 0) {
+        if (s->avctx->frame_rate < (24 * s->avctx->frame_rate_base) && s->picture_number > 0) {
             /* insert empty P pictures to slow down to the desired
                frame rate. Each fake pictures takes about 20 bytes */
             fps = frame_rate_tab[s->frame_rate_index];
-            n = (((int64_t)s->picture_number * fps) / s->frame_rate) - 1;
+            n = av_rescale((int64_t)s->picture_number * s->avctx->frame_rate_base, fps, s->avctx->frame_rate) / MPEG1_FRAME_RATE_BASE - 1;
             while (s->fake_picture_number < n) {
                 mpeg1_skip_picture(s, s->fake_picture_number - 
                                    s->gop_picture_number); 
@@ -1638,8 +1640,13 @@
     s->low_delay = get_bits1(&s->gb);
     frame_rate_ext_n = get_bits(&s->gb, 2);
     frame_rate_ext_d = get_bits(&s->gb, 5);
-    if (frame_rate_ext_d >= 1)
-        s->frame_rate = (s->frame_rate * frame_rate_ext_n) / frame_rate_ext_d;
+    av_reduce(
+        &s->avctx->frame_rate, 
+        &s->avctx->frame_rate_base, 
+        frame_rate_tab[s->frame_rate_index] * (frame_rate_ext_n+1),
+        MPEG1_FRAME_RATE_BASE * (frame_rate_ext_d+1),
+        1<<30);
+
     dprintf("sequence extension\n");
     s->mpeg2 = 1;
     s->avctx->sub_id = 2; /* indicates mpeg2 found */
@@ -1990,13 +1997,13 @@
         s->avctx = avctx;
         avctx->width = width;
         avctx->height = height;
-        if (s->frame_rate_index >= 9) {
-            /* at least give a valid frame rate (some old mpeg1 have this) */
-            avctx->frame_rate = 25 * FRAME_RATE_BASE;
-        } else {
-            avctx->frame_rate = frame_rate_tab[s->frame_rate_index];
-        }
-        s->frame_rate = avctx->frame_rate;
+        av_reduce(
+            &avctx->frame_rate, 
+            &avctx->frame_rate_base,
+            frame_rate_tab[s->frame_rate_index],
+            MPEG1_FRAME_RATE_BASE, //FIXME store in allready reduced form 
+            1<<30
+            );
         avctx->bit_rate = s->bit_rate;
         
         if (MPV_common_init(s) < 0)
--- a/mpeg12data.h	Tue Mar 11 12:09:13 2003 +0000
+++ b/mpeg12data.h	Wed Mar 12 15:16:19 2003 +0000
@@ -385,16 +385,28 @@
 { 0xc, 10 },
 };
 
-static const int frame_rate_tab[9] = {
-    0, 
-    24000 * FRAME_RATE_BASE / 1001,
-    24000 * FRAME_RATE_BASE / 1000,
-    25000 * FRAME_RATE_BASE / 1000,
-    30000 * FRAME_RATE_BASE / 1001,
-    30000 * FRAME_RATE_BASE / 1000,
-    50000 * FRAME_RATE_BASE / 1000,
-    60000 * FRAME_RATE_BASE / 1001,
-    60000 * FRAME_RATE_BASE / 1000,
+#define MPEG1_FRAME_RATE_BASE 1001
+
+static const int frame_rate_tab[16] = {
+        0,        
+    24000,
+    24024,
+    25025,
+    30000,
+    30030,
+    50050,
+    60000,
+    60060,
+  // Xing's 15fps: (9)
+    15015,
+  // libmpeg3's "Unofficial economy rates": (10-13)
+     5005,
+    10010,
+    12012,
+    15015,
+  // random, just to avoid segfault !never encode these
+    25025,
+    25025,
 };
 
 static const uint8_t non_linear_qscale[32] = {
--- a/mpegvideo.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/mpegvideo.c	Wed Mar 12 15:16:19 2003 +0000
@@ -504,7 +504,6 @@
 
     s->bit_rate = avctx->bit_rate;
     s->bit_rate_tolerance = avctx->bit_rate_tolerance;
-    s->frame_rate = avctx->frame_rate;
     s->width = avctx->width;
     s->height = avctx->height;
     if(avctx->gop_size > 600){
@@ -557,7 +556,8 @@
     switch(avctx->codec->id) {
     case CODEC_ID_MPEG1VIDEO:
         s->out_format = FMT_MPEG1;
-        avctx->delay=0; //FIXME not sure, should check the spec
+        s->low_delay= 0; //s->max_b_frames ? 0 : 1;
+        avctx->delay= s->low_delay ? 0 : (s->max_b_frames + 1);
         break;
     case CODEC_ID_MJPEG:
         s->out_format = FMT_MJPEG;
--- a/mpegvideo.h	Tue Mar 11 12:09:13 2003 +0000
+++ b/mpegvideo.h	Wed Mar 12 15:16:19 2003 +0000
@@ -192,7 +192,6 @@
     /* the following parameters must be initialized before encoding */
     int width, height;///< picture size. must be a multiple of 16 
     int gop_size;
-    int frame_rate;   ///< number of frames per second 
     int intra_only;   ///< if true, only intra pictures are generated 
     int bit_rate;     ///< wanted bit rate 
     int bit_rate_tolerance; ///< amount of +- bits (>0)
--- a/msmpeg4.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/msmpeg4.c	Wed Mar 12 15:16:19 2003 +0000
@@ -435,7 +435,7 @@
 
 void msmpeg4_encode_ext_header(MpegEncContext * s)
 {
-        put_bits(&s->pb, 5, s->frame_rate / FRAME_RATE_BASE); //yes 29.97 -> 29
+        put_bits(&s->pb, 5, s->avctx->frame_rate / s->avctx->frame_rate_base); //yes 29.97 -> 29
 
         put_bits(&s->pb, 11, FFMIN(s->bit_rate/1024, 2047));
 
--- a/ratecontrol.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/ratecontrol.c	Wed Mar 12 15:16:19 2003 +0000
@@ -164,7 +164,7 @@
                 bits= rce.i_tex_bits + rce.p_tex_bits;
 
                 q= get_qscale(s, &rce, rcc->pass1_wanted_bits/rcc->pass1_rc_eq_output_sum, i);
-                rcc->pass1_wanted_bits+= s->bit_rate/(s->frame_rate / (double)FRAME_RATE_BASE);
+                rcc->pass1_wanted_bits+= s->bit_rate/(s->avctx->frame_rate / (double)s->avctx->frame_rate_base);
             }
         }
 
@@ -197,7 +197,7 @@
     
 static void update_rc_buffer(MpegEncContext *s, int frame_size){
     RateControlContext *rcc= &s->rc_context;
-    const double fps= (double)s->frame_rate / FRAME_RATE_BASE;
+    const double fps= (double)s->avctx->frame_rate / (double)s->avctx->frame_rate_base;
     const double buffer_size= s->avctx->rc_buffer_size;
     const double min_rate= s->avctx->rc_min_rate/fps;
     const double max_rate= s->avctx->rc_max_rate/fps;
@@ -571,7 +571,7 @@
 
     get_qminmax(&qmin, &qmax, s, pict_type);
 
-    fps= (double)s->frame_rate / FRAME_RATE_BASE;
+    fps= (double)s->avctx->frame_rate / (double)s->avctx->frame_rate_base;
 //printf("input_pic_num:%d pic_num:%d frame_rate:%d\n", s->input_picture_number, s->picture_number, s->frame_rate);
         /* update predictors */
     if(picture_number>2){
@@ -698,7 +698,7 @@
 {
     RateControlContext *rcc= &s->rc_context;
     int i;
-    double fps= (double)s->frame_rate / FRAME_RATE_BASE;
+    double fps= (double)s->avctx->frame_rate / (double)s->avctx->frame_rate_base;
     double complexity[5]={0,0,0,0,0};   // aproximate bits at quant=1
     double avg_quantizer[5];
     uint64_t const_bits[5]={0,0,0,0,0}; // quantizer idependant bits
--- a/utils.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/utils.c	Wed Mar 12 15:16:19 2003 +0000
@@ -236,7 +236,8 @@
     s->error_concealment= 3;
     s->error_resilience= 1;
     s->workaround_bugs= FF_BUG_AUTODETECT;
-    s->frame_rate = 25 * FRAME_RATE_BASE;
+    s->frame_rate_base= 1;
+    s->frame_rate = 25;
     s->gop_size= 50;
     s->me_method= ME_EPZS;
     s->get_buffer= avcodec_default_get_buffer;
@@ -463,7 +464,7 @@
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
                      ", %dx%d, %0.2f fps",
                      enc->width, enc->height, 
-                     (float)enc->frame_rate / FRAME_RATE_BASE);
+                     (float)enc->frame_rate / enc->frame_rate_base);
         }
         if (encode) {
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
@@ -588,6 +589,65 @@
     }
 }
 
+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;
+
+    assert(den != 0);
+
+    if(den < 0){
+        den= -den;
+        nom= -nom;
+    }
+    
+    if(nom < 0){
+        nom= -nom;
+        sign= 1;
+    }
+    
+    for(;;){ //note is executed 1 or 2 times 
+        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(sign) nom= -nom;
+    
+    *dst_nom = nom;
+    *dst_den = den;
+    
+    return exact;
+}
+
+int64_t av_rescale(int64_t a, int b, int c){
+    uint64_t h, l;
+    assert(c > 0);
+    assert(b >=0);
+    
+    if(a<0) return -av_rescale(-a, b, c);
+    
+    h= a>>32;
+    if(h==0) return a*b/c;
+    
+    l= a&0xFFFFFFFF;
+    l *= b;
+    h *= b;
+
+    l += (h%c)<<32;
+
+    return ((h/c)<<32) + l/c;
+}
+
 static int raw_encode_init(AVCodecContext *s)
 {
     return 0;
--- a/wmv2.c	Tue Mar 11 12:09:13 2003 +0000
+++ b/wmv2.c	Wed Mar 12 15:16:19 2003 +0000
@@ -66,7 +66,7 @@
         
     init_put_bits(&pb, s->avctx->extradata, s->avctx->extradata_size, NULL, NULL);
 
-    put_bits(&pb, 5, s->frame_rate / FRAME_RATE_BASE); //yes 29.97 -> 29
+    put_bits(&pb, 5, s->avctx->frame_rate / s->avctx->frame_rate_base); //yes 29.97 -> 29
     put_bits(&pb, 11, FFMIN(s->bit_rate/1024, 2047));
     
     put_bits(&pb, 1, w->mspel_bit=1);