From af469427b345528797a6f0f33e8e6e5df623593d Mon Sep 17 00:00:00 2001
From: Juanjo <pulento@users.sourceforge.net>
Date: Wed, 20 Mar 2002 11:16:07 +0000
Subject: [PATCH] - Fix pts calculation on mpeg mux (A/V sync) - Thanks to
 Lennert Buytenhek - Fix temporal-reference-glitches for MPEG1 - Thanks to
 Lennert Buytenhek

Originally committed as revision 343 to svn://svn.ffmpeg.org/ffmpeg/trunk
---
 doc/TODO            |  1 -
 libav/mpeg.c        | 28 ++++++++++++++++++++--------
 libav/tick.h        | 31 +++++++++++++++++++++++++++++++
 libav/utils.c       | 28 ++++++++++++++++++++++++++++
 libavcodec/mpeg12.c |  2 +-
 5 files changed, 80 insertions(+), 10 deletions(-)
 create mode 100644 libav/tick.h

diff --git a/doc/TODO b/doc/TODO
index a15c6b61ed2..9e1bee5ae14 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 5ac9c62b182..2871278778d 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 00000000000..8b6d6b4421b
--- /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 <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;
+}
diff --git a/libav/utils.c b/libav/utils.c
index aafc4e78632..7315ebdc925 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 <unistd.h>
 #include <fcntl.h>
@@ -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 20ed5e4c6ee..76704c3b2a1 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 */
-- 
GitLab