- Fix temporal-reference-glitches for MPEG1 - Thanks to Lennert Buytenhek Originally committed as revision 343 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -14,7 +14,6 @@ Planned in next release: | |||||
| - find a solution to clear feed1.ffm if format change. | - find a solution to clear feed1.ffm if format change. | ||||
| - new grab architecture : use avformat instead of audio: and video: | - new grab architecture : use avformat instead of audio: and video: | ||||
| protocol. | protocol. | ||||
| - correct PTS handling to sync audio and video. | |||||
| - fix 0 size picture in AVIs = skip picture | - fix 0 size picture in AVIs = skip picture | ||||
| BUGS: | BUGS: | ||||
| @@ -17,6 +17,7 @@ | |||||
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| */ | */ | ||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "tick.h" | |||||
| #define MAX_PAYLOAD_SIZE 4096 | #define MAX_PAYLOAD_SIZE 4096 | ||||
| #define NB_STREAMS 2 | #define NB_STREAMS 2 | ||||
| @@ -27,7 +28,8 @@ typedef struct { | |||||
| UINT8 id; | UINT8 id; | ||||
| int max_buffer_size; /* in bytes */ | int max_buffer_size; /* in bytes */ | ||||
| int packet_number; | int packet_number; | ||||
| float pts; | |||||
| INT64 pts; | |||||
| Ticker pts_ticker; | |||||
| INT64 start_pts; | INT64 start_pts; | ||||
| } StreamInfo; | } StreamInfo; | ||||
| @@ -211,6 +213,20 @@ static int mpeg_mux_init(AVFormatContext *ctx) | |||||
| stream->packet_number = 0; | stream->packet_number = 0; | ||||
| stream->pts = 0; | stream->pts = 0; | ||||
| stream->start_pts = -1; | 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; | return 0; | ||||
| fail: | fail: | ||||
| @@ -316,7 +332,7 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, | |||||
| while (size > 0) { | while (size > 0) { | ||||
| /* set pts */ | /* set pts */ | ||||
| if (stream->start_pts == -1) | 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; | len = s->packet_data_max_size - stream->buffer_ptr; | ||||
| if (len > size) | if (len > size) | ||||
| 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) { | while (stream->buffer_ptr >= s->packet_data_max_size) { | ||||
| /* output the packet */ | /* output the packet */ | ||||
| if (stream->start_pts == -1) | if (stream->start_pts == -1) | ||||
| stream->start_pts = stream->pts * 90000.0; | |||||
| stream->start_pts = stream->pts; | |||||
| flush_packet(ctx, stream_index); | 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; | return 0; | ||||
| } | } | ||||
| @@ -0,0 +1,31 @@ | |||||
| /* tick.h - Compute successive integer multiples of a rational | |||||
| * number without long-term rounding error. | |||||
| * (c)2002 by Lennert Buytenhek <buytenh@gnu.org> | |||||
| * 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; | |||||
| } | |||||
| @@ -17,6 +17,7 @@ | |||||
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| */ | */ | ||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "tick.h" | |||||
| #ifndef CONFIG_WIN32 | #ifndef CONFIG_WIN32 | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| @@ -615,4 +616,31 @@ int get_frame_filename(char *buf, int buf_size, | |||||
| return -1; | 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; | |||||
| } | |||||
| @@ -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 */ | /* temporal reference */ | ||||
| put_bits(&s->pb, 10, (s->fake_picture_number - | put_bits(&s->pb, 10, (s->fake_picture_number - | ||||
| s->gop_picture_number) & 0x3ff); | s->gop_picture_number) & 0x3ff); | ||||
| s->fake_picture_number++; | |||||
| put_bits(&s->pb, 3, s->pict_type); | put_bits(&s->pb, 3, s->pict_type); | ||||
| put_bits(&s->pb, 16, 0xffff); /* non constant bit rate */ | put_bits(&s->pb, 16, 0xffff); /* non constant bit rate */ | ||||