diff --git a/doc/TODO b/doc/TODO index a15c6b61ed..9e1bee5ae1 100644 --- a/doc/TODO +++ b/doc/TODO @@ -14,7 +14,6 @@ Planned in next release: - find a solution to clear feed1.ffm if format change. - new grab architecture : use avformat instead of audio: and video: protocol. -- correct PTS handling to sync audio and video. - fix 0 size picture in AVIs = skip picture BUGS: diff --git a/libav/mpeg.c b/libav/mpeg.c index 5ac9c62b18..2871278778 100644 --- a/libav/mpeg.c +++ b/libav/mpeg.c @@ -17,6 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "avformat.h" +#include "tick.h" #define MAX_PAYLOAD_SIZE 4096 #define NB_STREAMS 2 @@ -27,7 +28,8 @@ typedef struct { UINT8 id; int max_buffer_size; /* in bytes */ int packet_number; - float pts; + INT64 pts; + Ticker pts_ticker; INT64 start_pts; } StreamInfo; @@ -211,6 +213,20 @@ static int mpeg_mux_init(AVFormatContext *ctx) stream->packet_number = 0; stream->pts = 0; stream->start_pts = -1; + + st = ctx->streams[i]; + switch (st->codec.codec_type) { + case CODEC_TYPE_AUDIO: + ticker_init(&stream->pts_ticker, + st->codec.sample_rate, + 90000 * st->codec.frame_size); + break; + case CODEC_TYPE_VIDEO: + ticker_init(&stream->pts_ticker, + st->codec.frame_rate, + 90000 * FRAME_RATE_BASE); + break; + } } return 0; fail: @@ -316,7 +332,7 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, while (size > 0) { /* set pts */ if (stream->start_pts == -1) - stream->start_pts = stream->pts * 90000.0; + stream->start_pts = stream->pts; len = s->packet_data_max_size - stream->buffer_ptr; if (len > size) len = size; @@ -327,16 +343,12 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, while (stream->buffer_ptr >= s->packet_data_max_size) { /* output the packet */ if (stream->start_pts == -1) - stream->start_pts = stream->pts * 90000.0; + stream->start_pts = stream->pts; flush_packet(ctx, stream_index); } } - if (st->codec.codec_type == CODEC_TYPE_AUDIO) { - stream->pts += (float)st->codec.frame_size / st->codec.sample_rate; - } else { - stream->pts += FRAME_RATE_BASE / (float)st->codec.frame_rate; - } + stream->pts += ticker_tick(&stream->pts_ticker, 1); return 0; } diff --git a/libav/tick.h b/libav/tick.h new file mode 100644 index 0000000000..8b6d6b4421 --- /dev/null +++ b/libav/tick.h @@ -0,0 +1,31 @@ +/* tick.h - Compute successive integer multiples of a rational + * number without long-term rounding error. + * (c)2002 by Lennert Buytenhek + * File licensed under the GPL, see http://www.fsf.org/ for more info. + * Dedicated to Marija Kulikova. + */ + +#include "avcodec.h" + +typedef struct Ticker { + int value; + int inrate; + int outrate; + int div; + int mod; +} Ticker; + +extern void ticker_init(Ticker *tick, INT64 inrate, INT64 outrate); + +extern inline int ticker_tick(Ticker *tick, int num) +{ + int n = num * tick->div; + + tick->value += num * tick->mod; + while (tick->value > 0) { + tick->value -= tick->inrate; + n++; + } + + return n; +} diff --git a/libav/utils.c b/libav/utils.c index aafc4e7863..7315ebdc92 100644 --- a/libav/utils.c +++ b/libav/utils.c @@ -17,6 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "avformat.h" +#include "tick.h" #ifndef CONFIG_WIN32 #include #include @@ -615,4 +616,31 @@ int get_frame_filename(char *buf, int buf_size, return -1; } +static int gcd(INT64 a, INT64 b) +{ + INT64 c; + while (1) { + c = a % b; + if (c == 0) + return b; + a = b; + b = c; + } +} + +void ticker_init(Ticker *tick, INT64 inrate, INT64 outrate) +{ + int g; + + g = gcd(inrate, outrate); + inrate /= g; + outrate /= g; + + tick->value = -outrate/2; + + tick->inrate = inrate; + tick->outrate = outrate; + tick->div = tick->outrate / tick->inrate; + tick->mod = tick->outrate % tick->inrate; +} diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 20ed5e4c6e..76704c3b2a 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -129,7 +129,6 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) } } - s->fake_picture_number++; } @@ -226,6 +225,7 @@ void mpeg1_encode_picture_header(MpegEncContext *s, int picture_number) /* temporal reference */ put_bits(&s->pb, 10, (s->fake_picture_number - s->gop_picture_number) & 0x3ff); + s->fake_picture_number++; put_bits(&s->pb, 3, s->pict_type); put_bits(&s->pb, 16, 0xffff); /* non constant bit rate */