From 14bea432f16d7c66f9099e427819028b6b4c3bdc Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 12 Mar 2003 15:16:19 +0000 Subject: [PATCH] per context frame_rate_base, this should finally fix frame_rate related av sync issues Originally committed as revision 1666 to svn://svn.ffmpeg.org/ffmpeg/trunk --- ffmpeg.c | 40 +++++++++++++++++-------- ffserver.c | 17 +++++++---- libavcodec/apiexample.c | 3 +- libavcodec/avcodec.h | 29 +++++++++++++++--- libavcodec/common.c | 2 +- libavcodec/common.h | 2 +- libavcodec/dv.c | 5 ++-- libavcodec/h263.c | 12 ++++---- libavcodec/mpeg12.c | 37 +++++++++++++---------- libavcodec/mpeg12data.h | 32 +++++++++++++------- libavcodec/mpegvideo.c | 4 +-- libavcodec/mpegvideo.h | 1 - libavcodec/msmpeg4.c | 2 +- libavcodec/ratecontrol.c | 8 ++--- libavcodec/utils.c | 64 ++++++++++++++++++++++++++++++++++++++-- libavcodec/wmv2.c | 2 +- libavformat/asf.c | 3 +- libavformat/avformat.h | 4 +-- libavformat/avidec.c | 16 ++++++---- libavformat/avienc.c | 10 ++----- libavformat/dv1394.c | 3 +- libavformat/ffm.c | 15 ++++------ libavformat/gif.c | 6 ++-- libavformat/gifdec.c | 3 +- libavformat/grab.c | 14 +++++---- libavformat/img.c | 13 ++++---- libavformat/mov.c | 8 ++--- libavformat/raw.c | 9 ++++-- libavformat/rm.c | 5 ++-- libavformat/rtp.c | 6 ++-- libavformat/swf.c | 12 ++++---- libavformat/utils.c | 23 +++++++-------- libavformat/yuv4mpeg.c | 20 +++++++++---- 33 files changed, 282 insertions(+), 148 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 602ce2a781..aa21dcdd2c 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -90,7 +90,8 @@ static int frame_topBand = 0; static int frame_bottomBand = 0; static int frame_leftBand = 0; static int frame_rightBand = 0; -static int frame_rate = 25 * FRAME_RATE_BASE; +static int frame_rate = 25; +static int frame_rate_base = 1; static int video_bit_rate = 200*1000; static int video_bit_rate_tolerance = 4000*1000; static int video_qscale = 0; @@ -746,7 +747,7 @@ static void do_video_stats(AVFormatContext *os, AVOutputStream *ost, if (ti1 < 0.01) ti1 = 0.01; - bitrate = (double)(frame_size * 8) * enc->frame_rate / FRAME_RATE_BASE / 1000.0; + bitrate = (double)(frame_size * 8) * enc->frame_rate / enc->frame_rate_base / 1000.0; avg_bitrate = (double)(total_size * 8) / ti1 / 1000.0; fprintf(fvstats, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", (double)total_size / 1024, ti1, bitrate, avg_bitrate); @@ -974,6 +975,7 @@ static int av_encode(AVFormatContext **output_files, break; case CODEC_TYPE_VIDEO: codec->frame_rate = icodec->frame_rate; + codec->frame_rate_base = icodec->frame_rate_base; codec->width = icodec->width; codec->height = icodec->height; break; @@ -1361,7 +1363,7 @@ static int av_encode(AVFormatContext **output_files, /* frame rate emulation */ if (ist->st->codec.rate_emu) { - int64_t pts = ((int64_t) ist->frame * FRAME_RATE_BASE * 1000000) / (ist->st->codec.frame_rate); + int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate); int64_t now = av_gettime() - ist->start; if (pts > now) usleep(pts - now); @@ -1673,7 +1675,9 @@ static void opt_debug(const char *arg) static void opt_frame_rate(const char *arg) { - frame_rate = (int)(strtod(arg, 0) * FRAME_RATE_BASE); + frame_rate_base = DEFAULT_FRAME_RATE_BASE; //FIXME not optimal + frame_rate = (int)(strtod(arg, 0) * frame_rate_base + 0.5); + //FIXME parse fractions } @@ -2051,7 +2055,7 @@ static void opt_input_file(const char *filename) { AVFormatContext *ic; AVFormatParameters params, *ap = ¶ms; - int err, i, ret, rfps; + int err, i, ret, rfps, rfps_base; if (!strcmp(filename, "-")) filename = "pipe:"; @@ -2061,6 +2065,7 @@ static void opt_input_file(const char *filename) ap->sample_rate = audio_sample_rate; ap->channels = audio_channels; ap->frame_rate = frame_rate; + ap->frame_rate_base = frame_rate_base; ap->width = frame_width; ap->height = frame_height; ap->image_format = image_format; @@ -2092,7 +2097,8 @@ static void opt_input_file(const char *filename) case CODEC_TYPE_VIDEO: frame_height = enc->height; frame_width = enc->width; - rfps = ic->streams[i]->r_frame_rate; + rfps = ic->streams[i]->r_frame_rate; + rfps_base = ic->streams[i]->r_frame_rate_base; enc->workaround_bugs = workaround_bugs; enc->error_resilience = error_resilience; enc->error_concealment = error_concealment; @@ -2106,13 +2112,15 @@ static void opt_input_file(const char *filename) if(bitexact) enc->flags|= CODEC_FLAG_BITEXACT; - if (enc->frame_rate != rfps) { + assert(enc->frame_rate_base == rfps_base); // should be true for now + if (enc->frame_rate != rfps) { fprintf(stderr,"\nSeems that stream %d comes from film source: %2.2f->%2.2f\n", - i, (float)enc->frame_rate / FRAME_RATE_BASE, - (float)rfps / FRAME_RATE_BASE); + i, (float)enc->frame_rate / enc->frame_rate_base, + (float)rfps / rfps_base); } /* update the current frame rate to match the stream frame rate */ - frame_rate = rfps; + frame_rate = rfps; + frame_rate_base = rfps_base; enc->rate_emu = rate_emu; break; @@ -2241,6 +2249,7 @@ static void opt_output_file(const char *filename) video_enc->bit_rate = video_bit_rate; video_enc->bit_rate_tolerance = video_bit_rate_tolerance; video_enc->frame_rate = frame_rate; + video_enc->frame_rate_base = frame_rate_base; video_enc->width = frame_width; video_enc->height = frame_height; @@ -2492,8 +2501,12 @@ static void prepare_grab(void) vp->width = enc->width; if (enc->height > vp->height) vp->height = enc->height; - if (enc->frame_rate > vp->frame_rate) - vp->frame_rate = enc->frame_rate; + + assert(enc->frame_rate_base == DEFAULT_FRAME_RATE_BASE); + if (enc->frame_rate > vp->frame_rate){ + vp->frame_rate = enc->frame_rate; + vp->frame_rate_base = enc->frame_rate_base; + } has_video = 1; break; default: @@ -2517,7 +2530,8 @@ static void prepare_grab(void) exit(1); } /* by now video grab has one stream */ - ic->streams[0]->r_frame_rate = vp->frame_rate; + ic->streams[0]->r_frame_rate = vp->frame_rate; + ic->streams[0]->r_frame_rate_base = vp->frame_rate_base; input_files[nb_input_files] = ic; dump_format(ic, nb_input_files, "", 0); nb_input_files++; diff --git a/ffserver.c b/ffserver.c index ee560e26bc..73e61e5a53 100644 --- a/ffserver.c +++ b/ffserver.c @@ -1725,7 +1725,7 @@ static void compute_stats(HTTPContext *c) case CODEC_TYPE_VIDEO: type = "video"; sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height, - st->codec.qmin, st->codec.qmax, st->codec.frame_rate / FRAME_RATE_BASE); + st->codec.qmin, st->codec.qmax, st->codec.frame_rate / st->codec.frame_rate_base); break; default: av_abort(); @@ -1950,7 +1950,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) (int64_t)s->pts_num * st->codec.sample_rate); break; case CODEC_TYPE_VIDEO: - st->pts_incr = (int64_t)s->pts_den * FRAME_RATE_BASE; + st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base; av_frac_init(&st->pts, st->pts.val, 0, (int64_t)s->pts_num * st->codec.frame_rate); break; @@ -2018,7 +2018,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) (int64_t)s->pts_num * st->codec.sample_rate); break; case CODEC_TYPE_VIDEO: - st->pts_incr = (int64_t)s->pts_den * FRAME_RATE_BASE; + st->pts_incr = (int64_t)s->pts_den * st->codec.frame_rate_base; av_frac_init(&st->pts, st->pts.val, 0, (int64_t)s->pts_num * st->codec.frame_rate); break; @@ -3219,6 +3219,7 @@ static int add_av_stream(FFStream *feed, AVStream *st) if (av1->width == av->width && av1->height == av->height && av1->frame_rate == av->frame_rate && + av1->frame_rate_base == av->frame_rate_base && av1->gop_size == av->gop_size) goto found; break; @@ -3406,6 +3407,7 @@ static void build_feed_streams(void) matches = 0; } else if (ccf->codec_type == CODEC_TYPE_VIDEO) { if (CHECK_CODEC(frame_rate) || + CHECK_CODEC(frame_rate_base) || CHECK_CODEC(width) || CHECK_CODEC(height)) { printf("Codec width, height and framerate do not match for stream %d\n", i); @@ -3553,8 +3555,10 @@ static void add_codec(FFStream *stream, AVCodecContext *av) case CODEC_TYPE_VIDEO: if (av->bit_rate == 0) av->bit_rate = 64000; - if (av->frame_rate == 0) - av->frame_rate = 5 * FRAME_RATE_BASE; + if (av->frame_rate == 0){ + av->frame_rate = 5; + av->frame_rate_base = 1; + } if (av->width == 0 || av->height == 0) { av->width = 160; av->height = 128; @@ -4017,7 +4021,8 @@ static int parse_ffconfig(const char *filename) } else if (!strcasecmp(cmd, "VideoFrameRate")) { get_arg(arg, sizeof(arg), &p); if (stream) { - video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE); + video_enc.frame_rate_base= DEFAULT_FRAME_RATE_BASE; + video_enc.frame_rate = (int)(strtod(arg, NULL) * video_enc.frame_rate_base); } } else if (!strcasecmp(cmd, "VideoGopSize")) { get_arg(arg, sizeof(arg), &p); diff --git a/libavcodec/apiexample.c b/libavcodec/apiexample.c index 306be47f91..27ec8241e1 100644 --- a/libavcodec/apiexample.c +++ b/libavcodec/apiexample.c @@ -192,7 +192,8 @@ void video_encode_example(const char *filename) 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 */ diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 0bae8dab4b..b10071da69 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -186,8 +186,6 @@ static const int Motion_Est_QTab[] = { ME_ZERO, ME_PHODS, ME_LOG, #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 @@ typedef struct AVFrame { FF_COMMON_FRAME } AVFrame; +#define DEFAULT_FRAME_RATE_BASE 1001000 /** * main external api structure. @@ -375,13 +374,21 @@ typedef struct AVCodecContext { /* 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_register_all(void); 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); /** diff --git a/libavcodec/common.c b/libavcodec/common.c index 96d0afcbe5..0681953846 100644 --- a/libavcodec/common.c +++ b/libavcodec/common.c @@ -341,7 +341,7 @@ void free_vlc(VLC *vlc) 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; } diff --git a/libavcodec/common.h b/libavcodec/common.h index 258302661a..b456af0f1b 100644 --- a/libavcodec/common.h +++ b/libavcodec/common.h @@ -876,7 +876,7 @@ static inline int clip(int a, int amin, int amax) /* 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) { diff --git a/libavcodec/dv.c b/libavcodec/dv.c index 9e89b3ac15..6d661f4cf4 100644 --- a/libavcodec/dv.c +++ b/libavcodec/dv.c @@ -537,16 +537,17 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, /* 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; diff --git a/libavcodec/h263.c b/libavcodec/h263.c index 154a8e9233..356eb73364 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -164,8 +164,8 @@ void h263_encode_picture_header(MpegEncContext * s, int picture_number) 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 @@ void ff_set_mpeg4_time(MpegEncContext * s, int picture_number){ 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; diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 6eb16c9dfc..65292ac430 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -203,8 +203,10 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) 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 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) /* 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 @@ static void mpeg_decode_sequence_extension(MpegEncContext *s) 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 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, 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) diff --git a/libavcodec/mpeg12data.h b/libavcodec/mpeg12data.h index d18640d074..16d607067f 100644 --- a/libavcodec/mpeg12data.h +++ b/libavcodec/mpeg12data.h @@ -385,16 +385,28 @@ static const uint8_t mbMotionVectorTable[17][2] = { { 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] = { diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 2639817265..df1c15880f 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -504,7 +504,6 @@ int MPV_encode_init(AVCodecContext *avctx) 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 @@ int MPV_encode_init(AVCodecContext *avctx) 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; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 6a556a8cdd..51d57e9ad4 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -192,7 +192,6 @@ typedef struct MpegEncContext { /* 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) diff --git a/libavcodec/msmpeg4.c b/libavcodec/msmpeg4.c index acf52d8136..47f8d2bec6 100644 --- a/libavcodec/msmpeg4.c +++ b/libavcodec/msmpeg4.c @@ -435,7 +435,7 @@ void msmpeg4_encode_picture_header(MpegEncContext * s, int picture_number) 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)); diff --git a/libavcodec/ratecontrol.c b/libavcodec/ratecontrol.c index d7fe11100c..80213dc008 100644 --- a/libavcodec/ratecontrol.c +++ b/libavcodec/ratecontrol.c @@ -164,7 +164,7 @@ int ff_rate_control_init(MpegEncContext *s) 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 inline double bits2qp(RateControlEntry *rce, double bits){ 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 @@ float ff_rate_estimate_qscale(MpegEncContext *s) 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 @@ static int init_pass2(MpegEncContext *s) { 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 diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 70de6ca13d..29efd04c38 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -236,7 +236,8 @@ void avcodec_get_context_defaults(AVCodecContext *s){ 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 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) 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 @@ void avcodec_flush_buffers(AVCodecContext *avctx) } } +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; diff --git a/libavcodec/wmv2.c b/libavcodec/wmv2.c index be8c71364f..96b6c8ca3b 100644 --- a/libavcodec/wmv2.c +++ b/libavcodec/wmv2.c @@ -66,7 +66,7 @@ static int encode_ext_header(Wmv2Context *w){ 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); diff --git a/libavformat/asf.c b/libavformat/asf.c index b9cd71e432..c2a3318d87 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -621,8 +621,7 @@ static int asf_write_packet(AVFormatContext *s, int stream_index, duration = (codec->frame_number * codec->frame_size * int64_t_C(10000000)) / codec->sample_rate; } else { - duration = codec->frame_number * - ((int64_t_C(10000000) * FRAME_RATE_BASE) / codec->frame_rate); + duration = av_rescale(codec->frame_number * codec->frame_rate_base, 10000000, codec->frame_rate); } if (duration > asf->duration) asf->duration = duration; diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f9d435a9b2..287bb80b0f 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -77,6 +77,7 @@ typedef struct AVProbeData { typedef struct AVFormatParameters { int frame_rate; + int frame_rate_base; int sample_rate; int channels; int width; @@ -159,6 +160,7 @@ typedef struct AVStream { int id; /* format specific stream id */ AVCodecContext codec; /* codec context */ int r_frame_rate; /* real frame rate of the stream */ + int r_frame_rate_base;/* real frame rate base of the stream */ uint64_t time_length; /* real length of the stream in miliseconds */ void *priv_data; /* internal data used in av_find_stream_info() */ @@ -332,8 +334,6 @@ extern AVOutputFormat yuv4mpegpipe_oformat; #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) #define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24)) -int av_gcd(int a, int b); - void av_register_input_format(AVInputFormat *format); void av_register_output_format(AVOutputFormat *format); AVOutputFormat *guess_stream_format(const char *short_name, diff --git a/libavformat/avidec.c b/libavformat/avidec.c index 6d23f07079..bec8c77040 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -133,12 +133,16 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) scale= get_le32(pb); /* scale */ rate= get_le32(pb); /* rate */ - if(scale && rate) - st->codec.frame_rate= (rate * (uint64_t)FRAME_RATE_BASE + scale/2) / scale; - else if(frame_period) - st->codec.frame_rate = (1000000LL * FRAME_RATE_BASE + frame_period/2) / frame_period; - else - st->codec.frame_rate = 25 * FRAME_RATE_BASE; + if(scale && rate){ + st->codec.frame_rate = rate; + st->codec.frame_rate_base= scale; + }else if(frame_period){ + st->codec.frame_rate = 1000000; + st->codec.frame_rate_base= frame_period; + }else{ + st->codec.frame_rate = 25; + st->codec.frame_rate_base = 1; + } url_fskip(pb, size - 7 * 4); break; diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 2f36801bcb..f885d657a9 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -218,7 +218,7 @@ static int avi_write_header(AVFormatContext *s) nb_frames = 0; if(video_enc){ - put_le32(pb, (uint32_t)(int64_t_C(1000000) * FRAME_RATE_BASE / video_enc->frame_rate)); + put_le32(pb, (uint32_t)(int64_t_C(1000000) * video_enc->frame_rate_base / video_enc->frame_rate)); } else { put_le32(pb, 0); } @@ -244,8 +244,6 @@ static int avi_write_header(AVFormatContext *s) /* stream list */ for(i=0;iframe_rate, FRAME_RATE_BASE); - - put_le32(pb, FRAME_RATE_BASE / gcd); /* scale */ - put_le32(pb, stream->frame_rate / gcd); /* rate */ + put_le32(pb, stream->frame_rate_base); /* scale */ + put_le32(pb, stream->frame_rate); /* rate */ put_le32(pb, 0); /* start */ avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ diff --git a/libavformat/dv1394.c b/libavformat/dv1394.c index 7048c342c8..31d583c265 100644 --- a/libavformat/dv1394.c +++ b/libavformat/dv1394.c @@ -138,7 +138,8 @@ static int dv1394_read_header(AVFormatContext * context, AVFormatParameters * ap vst->codec.codec_id = CODEC_ID_DVVIDEO; vst->codec.width = dv->width; vst->codec.height = dv->height; - vst->codec.frame_rate = dv->frame_rate * FRAME_RATE_BASE; + vst->codec.frame_rate = dv->frame_rate; + vst->codec.frame_rate_base = 1; vst->codec.bit_rate = 25000000; /* Consumer DV is 25Mbps */ ast->codec.codec_type = CODEC_TYPE_AUDIO; diff --git a/libavformat/ffm.c b/libavformat/ffm.c index f2615673af..de2ea6bef1 100644 --- a/libavformat/ffm.c +++ b/libavformat/ffm.c @@ -140,8 +140,6 @@ static int ffm_write_header(AVFormatContext *s) /* list of streams */ for(i=0;inb_streams;i++) { - int gcd; - st = s->streams[i]; fst = av_mallocz(sizeof(FFMStream)); if (!fst) @@ -158,9 +156,8 @@ static int ffm_write_header(AVFormatContext *s) /* specific info */ switch(codec->codec_type) { case CODEC_TYPE_VIDEO: - gcd= av_gcd(FRAME_RATE_BASE, codec->frame_rate); - put_be32(pb, FRAME_RATE_BASE / gcd); - put_be32(pb, codec->frame_rate / gcd); + put_be32(pb, codec->frame_rate_base); + put_be32(pb, codec->frame_rate); put_be16(pb, codec->width); put_be16(pb, codec->height); put_be16(pb, codec->gop_size); @@ -229,7 +226,7 @@ static int ffm_write_packet(AVFormatContext *s, int stream_index, if (st->codec.codec_type == CODEC_TYPE_AUDIO) { duration = ((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0); } else { - duration = (1000000.0 * FRAME_RATE_BASE / (float)st->codec.frame_rate); + duration = (1000000.0 * st->codec.frame_rate_base / (float)st->codec.frame_rate); } pts = fst->pts; @@ -394,7 +391,6 @@ static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap) /* read each stream */ for(i=0;inb_streams;i++) { char rc_eq_buf[128]; - int rate, scale; st = av_mallocz(sizeof(AVStream)); if (!st) @@ -416,9 +412,8 @@ static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap) /* specific info */ switch(codec->codec_type) { case CODEC_TYPE_VIDEO: - scale= get_be32(pb); - rate= get_be32(pb); - codec->frame_rate = (rate * (int64_t)FRAME_RATE_BASE) / scale; + codec->frame_rate_base = get_be32(pb); + codec->frame_rate = get_be32(pb); codec->width = get_be16(pb); codec->height = get_be16(pb); codec->gop_size = get_be16(pb); diff --git a/libavformat/gif.c b/libavformat/gif.c index 47b32eff79..1df8827a33 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -296,7 +296,7 @@ static int gif_write_header(AVFormatContext *s) GIFContext *gif = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc, *video_enc; - int i, width, height, rate; + int i, width, height/*, rate*/; /* XXX: do we reject audio streams or just ignore them ? if(s->nb_streams > 1) @@ -318,7 +318,7 @@ static int gif_write_header(AVFormatContext *s) } else { width = video_enc->width; height = video_enc->height; - rate = video_enc->frame_rate; +// rate = video_enc->frame_rate; } /* XXX: is it allowed ? seems to work so far... */ @@ -351,7 +351,7 @@ static int gif_write_video(AVFormatContext *s, /* XXX: should use delay, in order to be more accurate */ /* instead of using the same rounded value each time */ /* XXX: don't even remember if I really use it for now */ - jiffies = (70*FRAME_RATE_BASE/enc->frame_rate) - 1; + jiffies = (70*enc->frame_rate_base/enc->frame_rate) - 1; put_le16(pb, jiffies); diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index b827845fe9..0ee59bc5f3 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -535,7 +535,8 @@ static int gif_read_header(AVFormatContext * s1, st->codec.codec_type = CODEC_TYPE_VIDEO; st->codec.codec_id = CODEC_ID_RAWVIDEO; - st->codec.frame_rate = 5 * FRAME_RATE_BASE; + st->codec.frame_rate = 5; + st->codec.frame_rate_base = 1; /* XXX: check if screen size is always valid */ st->codec.width = s->screen_width; st->codec.height = s->screen_height; diff --git a/libavformat/grab.c b/libavformat/grab.c index 7b8a1bcca9..3a99704520 100644 --- a/libavformat/grab.c +++ b/libavformat/grab.c @@ -31,6 +31,7 @@ typedef struct { int use_mmap; int width, height; int frame_rate; + int frame_rate_base; int64_t time_frame; int frame_size; struct video_capability video_cap; @@ -59,7 +60,7 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) AVStream *st; int width, height; int video_fd, frame_size; - int ret, frame_rate; + int ret, frame_rate, frame_rate_base; int desired_palette; struct video_audio audio; const char *video_device; @@ -69,7 +70,8 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) width = ap->width; height = ap->height; - frame_rate = ap->frame_rate; + frame_rate = ap->frame_rate; + frame_rate_base = ap->frame_rate_base; st = av_new_stream(s1, 0); if (!st) @@ -77,7 +79,8 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) s->width = width; s->height = height; - s->frame_rate = frame_rate; + s->frame_rate = frame_rate; + s->frame_rate_base = frame_rate_base; video_device = ap->device; if (!video_device) @@ -240,7 +243,8 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) st->codec.codec_id = CODEC_ID_RAWVIDEO; st->codec.width = width; st->codec.height = height; - st->codec.frame_rate = frame_rate; + st->codec.frame_rate = frame_rate; + st->codec.frame_rate_base = frame_rate_base; av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */ @@ -283,7 +287,7 @@ static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) VideoData *s = s1->priv_data; int64_t curtime, delay; struct timespec ts; - int64_t per_frame = (int64_t_C(1000000) * FRAME_RATE_BASE) / s->frame_rate; + int64_t per_frame = (int64_t_C(1000000) * s->frame_rate_base) / s->frame_rate; /* Calculate the time of the next frame */ s->time_frame += per_frame; diff --git a/libavformat/img.c b/libavformat/img.c index 178cee8911..36e501f109 100644 --- a/libavformat/img.c +++ b/libavformat/img.c @@ -124,10 +124,13 @@ static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) st->codec.pix_fmt = s->pix_fmt; s->img_size = avpicture_get_size(s->pix_fmt, s->width, s->height); - if (!ap || !ap->frame_rate) - st->codec.frame_rate = 25 * FRAME_RATE_BASE; - else - st->codec.frame_rate = ap->frame_rate; + if (!ap || !ap->frame_rate){ + st->codec.frame_rate = 25; + st->codec.frame_rate_base = 1; + }else{ + st->codec.frame_rate = ap->frame_rate; + st->codec.frame_rate_base = ap->frame_rate_base; + } return 0; fail1: @@ -182,7 +185,7 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) av_free_packet(pkt); return -EIO; /* signal EOF */ } else { - pkt->pts = ((int64_t)s->img_number * s1->pts_den * FRAME_RATE_BASE) / (s1->streams[0]->codec.frame_rate * s1->pts_num); + pkt->pts = av_rescale((int64_t)s->img_number * s1->streams[0]->codec.frame_rate_base, s1->pts_den, s1->streams[0]->codec.frame_rate) / s1->pts_num; s->img_number++; return 0; } diff --git a/libavformat/mov.c b/libavformat/mov.c index 0e43c54c4f..fe99673fa3 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -686,7 +686,8 @@ static int parse_stsd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, get_be16(pb); /* depth */ get_be16(pb); /* colortable id */ - st->codec.frame_rate = 25 * FRAME_RATE_BASE; + st->codec.frame_rate = 25; + st->codec.frame_rate_base = 1; size -= (16+8*4+2+32+2*2); while (size >= 8) { @@ -932,9 +933,8 @@ printf("track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); sample_duration = get_be32(pb); if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) { - st->codec.frame_rate = FRAME_RATE_BASE * c->streams[c->total_streams]->time_scale; - if (sample_duration) - st->codec.frame_rate /= sample_duration; + st->codec.frame_rate_base = sample_duration ? sample_duration : 1; + st->codec.frame_rate = c->streams[c->total_streams]->time_scale; #ifdef DEBUG printf("VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration); #endif diff --git a/libavformat/raw.c b/libavformat/raw.c index f32f5eb599..a1dcf871c4 100644 --- a/libavformat/raw.c +++ b/libavformat/raw.c @@ -61,7 +61,8 @@ static int raw_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec.channels = ap->channels; break; case CODEC_TYPE_VIDEO: - st->codec.frame_rate = ap->frame_rate; + st->codec.frame_rate = ap->frame_rate; + st->codec.frame_rate_base = ap->frame_rate_base; st->codec.width = ap->width; st->codec.height = ap->height; break; @@ -151,9 +152,11 @@ static int video_read_header(AVFormatContext *s, /* for mpeg4 specify it too (most mpeg4 streams dont have the fixed_vop_rate set ...)*/ if (st->codec.codec_id == CODEC_ID_MJPEG || st->codec.codec_id == CODEC_ID_MPEG4) { if (ap) { - st->codec.frame_rate = ap->frame_rate; + st->codec.frame_rate = ap->frame_rate; + st->codec.frame_rate_base = ap->frame_rate_base; } else { - st->codec.frame_rate = 25 * FRAME_RATE_BASE; + st->codec.frame_rate = 25; + st->codec.frame_rate_base = 1; } } return 0; diff --git a/libavformat/rm.c b/libavformat/rm.c index f5ae3a3f33..47b510b323 100644 --- a/libavformat/rm.c +++ b/libavformat/rm.c @@ -306,7 +306,7 @@ static int rm_write_header(AVFormatContext *s) break; case CODEC_TYPE_VIDEO: rm->video_stream = stream; - stream->frame_rate = (float)codec->frame_rate / (float)FRAME_RATE_BASE; + stream->frame_rate = (float)codec->frame_rate / (float)codec->frame_rate_base; /* XXX: dummy values */ stream->packet_max_size = 4096; stream->nb_packets = 0; @@ -582,7 +582,8 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) goto fail1; st->codec.width = get_be16(pb); st->codec.height = get_be16(pb); - st->codec.frame_rate = get_be16(pb) * FRAME_RATE_BASE; + st->codec.frame_rate_base= 1; + st->codec.frame_rate = get_be16(pb) * st->codec.frame_rate_base; st->codec.codec_type = CODEC_TYPE_VIDEO; get_be32(pb); get_be16(pb); diff --git a/libavformat/rtp.c b/libavformat/rtp.c index 87d28a3f77..45372b4ed6 100644 --- a/libavformat/rtp.c +++ b/libavformat/rtp.c @@ -560,9 +560,8 @@ static void rtp_send_mpegvideo(AVFormatContext *s1, q += len; /* 90 KHz time stamp */ - /* XXX: overflow */ s->timestamp = s->base_timestamp + - (s->cur_timestamp * 90000LL * FRAME_RATE_BASE) / st->codec.frame_rate; + av_rescale((int64_t)s->cur_timestamp * st->codec.frame_rate_base, 90000, st->codec.frame_rate); rtp_send_data(s1, s->buf, q - s->buf); buf1 += len; @@ -586,9 +585,8 @@ static void rtp_send_raw(AVFormatContext *s1, len = size; /* 90 KHz time stamp */ - /* XXX: overflow */ s->timestamp = s->base_timestamp + - (s->cur_timestamp * 90000LL * FRAME_RATE_BASE) / st->codec.frame_rate; + av_rescale((int64_t)s->cur_timestamp * st->codec.frame_rate_base, 90000, st->codec.frame_rate); rtp_send_data(s1, buf1, len); buf1 += len; diff --git a/libavformat/swf.c b/libavformat/swf.c index 9b86b58bee..60d931e2bf 100644 --- a/libavformat/swf.c +++ b/libavformat/swf.c @@ -194,7 +194,7 @@ static int swf_write_header(AVFormatContext *s) AVCodecContext *enc, *audio_enc, *video_enc; PutBitContext p; uint8_t buf1[256]; - int i, width, height, rate; + int i, width, height, rate, rate_base; swf = av_malloc(sizeof(SWFContext)); if (!swf) @@ -215,11 +215,13 @@ static int swf_write_header(AVFormatContext *s) /* currenty, cannot work correctly if audio only */ width = 320; height = 200; - rate = 10 * FRAME_RATE_BASE; + rate = 10; + rate_base= 1; } else { width = video_enc->width; height = video_enc->height; rate = video_enc->frame_rate; + rate_base = video_enc->frame_rate_base; } put_tag(pb, "FWS"); @@ -228,9 +230,9 @@ static int swf_write_header(AVFormatContext *s) (will be patched if not streamed) */ put_swf_rect(pb, 0, width, 0, height); - put_le16(pb, (rate * 256) / FRAME_RATE_BASE); /* frame rate */ + put_le16(pb, (rate * 256) / rate_base); /* frame rate */ swf->duration_pos = url_ftell(pb); - put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / FRAME_RATE_BASE)); /* frame count */ + put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ /* define a shape with the jpeg inside */ @@ -305,7 +307,7 @@ static int swf_write_header(AVFormatContext *s) put_swf_tag(s, TAG_STREAMHEAD); put_byte(&s->pb, 0); put_byte(&s->pb, v); - put_le16(&s->pb, (audio_enc->sample_rate * FRAME_RATE_BASE) / rate); /* avg samples per frame */ + put_le16(&s->pb, (audio_enc->sample_rate * rate_base) / rate); /* avg samples per frame */ put_swf_end_tag(s); diff --git a/libavformat/utils.c b/libavformat/utils.c index 5642894ec9..1c1c406606 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -614,10 +614,12 @@ int av_find_stream_info(AVFormatContext *ic) #endif /* stop after 40 frames */ if (st->codec_info_nb_real_frames >= 40) { - st->r_frame_rate = (st->codec.frame_rate * - st->codec_info_nb_real_frames) / - (st->codec_info_nb_real_frames + - (st->codec_info_nb_repeat_frames >> 1)); + av_reduce( + &st->r_frame_rate, + &st->r_frame_rate_base, + (int64_t)st->codec.frame_rate * st->codec_info_nb_real_frames, + st->codec_info_nb_real_frames + (st->codec_info_nb_repeat_frames >> 1), + 1<<30); goto close_codec; } } else { @@ -645,8 +647,10 @@ int av_find_stream_info(AVFormatContext *ic) for(i=0;inb_streams;i++) { st = ic->streams[i]; if (st->codec.codec_type == CODEC_TYPE_VIDEO) { - if (!st->r_frame_rate) - st->r_frame_rate = st->codec.frame_rate; + if (!st->r_frame_rate){ + st->r_frame_rate = st->codec.frame_rate; + st->r_frame_rate_base = st->codec.frame_rate_base; + } } } @@ -820,7 +824,7 @@ int av_write_frame(AVFormatContext *s, int stream_index, const uint8_t *buf, break; case CODEC_TYPE_VIDEO: av_frac_add(&st->pts, - (int64_t)s->pts_den * FRAME_RATE_BASE); + (int64_t)s->pts_den * st->codec.frame_rate_base); break; default: break; @@ -1316,11 +1320,6 @@ void av_frac_add(AVFrac *f, int64_t incr) f->num = num; } -int av_gcd(int a, int b){ - if(b) return av_gcd(b, a%b); - else return a; -} - /** * register a new image format * @param img_fmt Image format descriptor diff --git a/libavformat/yuv4mpeg.c b/libavformat/yuv4mpeg.c index 1659ca7885..2cdaf9b097 100644 --- a/libavformat/yuv4mpeg.c +++ b/libavformat/yuv4mpeg.c @@ -26,7 +26,7 @@ static int yuv4_write_header(AVFormatContext *s) { AVStream *st; int width, height; - int raten, rated, aspectn, aspectd, fps, fps1, n; + int raten, rated, aspectn, aspectd, fps, fps1, n, gcd; char buf[Y4M_LINE_MAX+1]; if (s->nb_streams != 1) @@ -35,9 +35,13 @@ static int yuv4_write_header(AVFormatContext *s) st = s->streams[0]; width = st->codec.width; height = st->codec.height; - + +#if 1 + //this is identical to the code below for exact fps + av_reduce(&raten, &rated, st->codec.frame_rate, st->codec.frame_rate_base, (1UL<<31)-1); +#else fps = st->codec.frame_rate; - fps1 = (((float)fps / FRAME_RATE_BASE) * 1000); + fps1 = (((float)fps / st->codec.frame_rate_base) * 1000); /* Sorry about this messy code, but mpeg2enc is very picky about * the framerates it accepts. */ @@ -75,13 +79,17 @@ static int yuv4_write_header(AVFormatContext *s) rated = 1; break; default: - raten = fps1; /* this setting should work, but often doesn't */ - rated = 1000; + raten = st->codec.frame_rate; /* this setting should work, but often doesn't */ + rated = st->codec.frame_rate_base; + gcd= av_gcd(raten, rated); + raten /= gcd; + rated /= gcd; break; } +#endif aspectn = 1; - aspectd = 1; /* ffmpeg always uses a 1:1 aspect ratio */ + aspectd = 1; /* ffmpeg always uses a 1:1 aspect ratio */ //FIXME not true anymore /* construct stream header, if this is the first frame */ n = snprintf(buf, sizeof(buf), "%s W%d H%d F%d:%d I%s A%d:%d\n",