Fix for AV-sync with FFMPEGrec

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



Hi,

As I've been promising myself for ages, I went hunting the cause of
AV-sync drift with FFMPEGrec.

The problem was in ffmpeg's libav - the audio PTS was tracked using a
float; accumulating error sent the sync steadily off.

I've done a quick change to use double instead of float - in testing, this
holds lipsync for 3 hours at least.  Would someone like to test this - I'd
like to have some confirmations from others and then I'll try get it into
the ffmpeg CVS.

Brian Murrell, how about you?  (I think you'll be interested in the next
patch I'll send, too!)

libav isn't documented and I'm not sure whether this change will affect
other users of this library.  I would really like to get rid of the float
pts and track frames by integer count, working out the pts from "scratch"
rather than incrememntally.  I'll ask about that on the ffmpeg list.

Anyway - for me this works nice.

Regards,
Steve
Index: libav/mpeg.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libav/mpeg.c,v
retrieving revision 1.2
diff -u -r1.2 mpeg.c
--- libav/mpeg.c	2001/08/13 21:37:10	1.2
+++ libav/mpeg.c	2001/12/30 00:41:11
@@ -16,6 +16,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+/* Steve Davies <steve@xxxxxxxxxxxxx> - 2001-12-29 -
+     Adjusted pts calcs from float to double to "fix"
+     AV sync trouble
+*/
+
 #include "avformat.h"
 
 #define MAX_PAYLOAD_SIZE 4096
@@ -27,7 +33,7 @@
     UINT8 id;
     int max_buffer_size; /* in bytes */
     int packet_number;
-    float pts;
+    double pts;
     INT64 start_pts;
 } StreamInfo;
 
@@ -233,8 +239,8 @@
     timestamp = stream->start_pts;
 
 #if 0
-    printf("packet ID=%2x PTS=%0.3f\n", 
-           id, timestamp / 90000.0);
+    printf("\npacket ID=%2x PTS=%0.18f, %lli\n", 
+           id, (double)(timestamp / 90000.0), timestamp);
 #endif
 
     buf_ptr = buffer;
@@ -314,7 +320,12 @@
     while (size > 0) {
         /* set pts */
         if (stream->start_pts == -1)
-            stream->start_pts = stream->pts * 90000.0;
+	  // 3000? tries to compensate for accumulating rounding error in the double pts.
+	  // after 1 hour audio ptses are off by around 40msec.  We add 3000 which is
+	  // 3000/90000=33msec and result is that audio starts slightly behind and drifts
+	  // to exact after 50 mins or so.  40 msec isn't noticable, whether ahead or behind,
+	  // so this little tweak should mean acceptable sync for 3-4 hours of recording.
+	  stream->start_pts = stream->pts * 90000.0 + 3000.0;
         len = s->packet_data_max_size - stream->buffer_ptr;
         if (len > size)
             len = size;
@@ -325,15 +336,17 @@
         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 * 90000.0 + 3000.0;
             flush_packet(ctx, stream_index);
         }
     }
 
     if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
-        stream->pts += (float)st->codec.frame_size / st->codec.sample_rate;
+        //printf("\nbefore, stream->pts = %0.15f\n", stream->pts);
+        stream->pts += (double)st->codec.frame_size / st->codec.sample_rate;
+        //printf("after, stream->pts = %0.15f\n", stream->pts);
     } else {
-        stream->pts += FRAME_RATE_BASE / (float)st->codec.frame_rate;
+        stream->pts += (double)FRAME_RATE_BASE / st->codec.frame_rate;
     }
     return 0;
 }

[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux