News:

--

Main Menu

Investigating a source of audio drift

Started by KoolAidMan, December 29, 2012, 08:56:27 PM

Previous topic - Next topic

KoolAidMan

I have a video file which encodes fine in 2.5, but in 2.6 I am seeing a significant amount of audio drift whenever there are null frames. I believe the drift is due to a bug in the MuxerAvi. Here is the log:

 [setAudioStreamInfo]  [ODML] Audio track 0, using ODML placeholder of size 16384 bytes, odmltrack=1, pos=0x4142
[ODML]write dummy chunk at file position 33098 with data size 260
 [saveBegin]  SuperIndex position so far 0 : 212
 [saveBegin]  SuperIndex position so far 1 : 16706
 [saveBegin]  SuperIndex position so far 2 : 0
[AviMuxer] Saving
 [save]  [AviMuxer]avg fps=59941
 [initUI]  Muxer, creating UI, video duration is  02:27:06,705
 [startThread]  Starting thread...
 [startThread]  Thread created and started
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
 [encode]  [x264] Null frame
[ODML]write dummy chunk at file position 33386 with data size 131072
 [goToTime]   go to time 0.28 secs
 [goToTime]  => seg 0, rel time 0.28 secs
 [resetAfterSeek]   flushing after seek
 [fillAudio]  [AviMuxer] Audio skew!
[audioClock] Drift detected :0 vs 414097, delta=414097
Percent:0
[ODML]write dummy chunk at file position 261416 with data size 131072
 [fillAudio]  [AviMuxer] Audio skew!
[audioClock] Drift detected :446097 vs 414097, delta=-32000
Percent:0

KoolAidMan

I believe this bug may be related to a warning in the MuxerAvi.


bool muxerAvi::fillAudio(uint64_t targetDts)
{
// Now send audio until they all have DTS > lastVideoDts+increment
            for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
            {
                ADM_audioStream*a=aStreams[audioIndex];
                uint32_t fq=a->getInfo()->frequency;
                int nb=0;
                audioClock *clk=clocks[audioIndex];
                aviAudioPacket *aPacket=audioPackets+audioIndex;
                if(true==aPacket->eos) return true;
                while(1)
                {
                    if(false==aPacket->present)
                    {
                        if(!a->getPacket(aPacket->buffer,
                                         &(aPacket->sizeInBytes),
                                         AUDIO_BUFFER_SIZE,
                                         &(aPacket->nbSamples),
                                         &(aPacket->dts)))
                        {
                                ADM_warning("Cannot get audio packet for stream %d\n",audioIndex);
                                aPacket->eos=true;
                                break;
                        }
                            if(aPacket->dts!=ADM_NO_PTS)
                            {
                                aPacket->dts+=audioDelay;
                            }
                            aprintf("[Audio] Packet size %"PRIu32" sample:%"PRIu32" dts:%"PRIu64" target :%"PRIu64"\n",
                                            aPacket->sizeInBytes,aPacket->nbSamples,aPacket->dts,targetDts);
                            if(aPacket->dts!=ADM_NO_PTS)
                                if( abs(aPacket->dts-clk->getTimeUs())>32000)
                                {
                                    ADM_warning("[AviMuxer] Audio skew!\n");
                                    clk->setTimeUs(aPacket->dts);
#warning FIXME add padding
                                }
                            aPacket->present=true;
                    }
                    // We now have a packet stored
                    if(aPacket->dts!=ADM_NO_PTS)
                        if(aPacket->dts>targetDts) break; // this one is in the future
                    nb=writter.saveAudioFrame(audioIndex,aPacket->sizeInBytes,aPacket->buffer) ;
                    encoding->pushAudioFrame(aPacket->sizeInBytes);
                    clk->advanceBySample(aPacket->nbSamples);
                    aPacket->present=false;
                    //printf("%u vs %u\n",audioDts/1000,(lastVideoDts+videoIncrement)/1000);
                }
            }

            return true;
}


Seeing if there's a change I can make to stop the audio drift...

mean

The delta is the difference between the expected DTS and the actual DTS
If the audio is in copy mode, it could mean the source is discontinuous or a bug in the reader part
(or you played with DTS :) )

The #warning says there should be some audio frame duplication going on to fill the gap

KoolAidMan

This drift is happening in 2.6.1-- without any modifications from me. I didn't play with the dts this time ;). I'll see if adding the frame duplication resolves the drifting issue.

KoolAidMan

#4
This patch fixes the audio drift for my video in 2.6. Of course, the dts is now non-monotonic, so I need to make some adjustments to the patch tomorrow before I submit it to the patch gallery.


Index: avidemux/common/ADM_audioFilter/src/audiocopy.cpp
===================================================================
--- avidemux/common/ADM_audioFilter/src/audiocopy.cpp (revision 8341)
+++ avidemux/common/ADM_audioFilter/src/audiocopy.cpp (working copy)
@@ -34,12 +34,13 @@
                         ADM_audioStream *in;
                         uint64_t        startTime;
                         int64_t         shift;
+                        bool            dupe;
         public:

                        ADM_audioStreamCopy(ADM_audioStream *input,uint64_t startTime, int64_t shift); 
virtual                 WAVHeader                *getInfo(void) {return in->getInfo();};
virtual uint8_t         getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,uint32_t *nbSample,uint64_t *dts);
-//virtual bool            goToTime(uint64_t nbUs);
+virtual bool            goToTime(uint64_t nbUs);
virtual bool             getExtraData(uint32_t *l, uint8_t **d);
          uint64_t        getDurationInUs(void);
          bool            isCBR();
@@ -53,8 +54,14 @@
     this->startTime=startTime;
     in->goToTime(startTime);
     this->shift=shift;
+    this->dupe=false;
}

+bool  ADM_audioStreamCopy::goToTime(uint64_t nbUs)
+{
+    return this->in->goToTime(nbUs);
+}
+
bool ADM_audioStreamCopy::isCBR()
{
     return in->isCBR();
@@ -74,14 +81,29 @@
     if(false==in->getPacket(buffer,size,sizeMax,nbSample,dts)) return false;
     if(*dts!=ADM_NO_PTS)
     {
-       
         int64_t corrected=*dts;
         corrected+=shift;
-        if(corrected<startTime) goto again; // cant have <0 dts
-        *dts=corrected-startTime;
+
+        if(corrected<0)
+        {
+            dupe=true;
+        }
+        else if(dupe)
+        {
+            shift=*dts;
+            in->goToTime(corrected);
+            dupe=false;
+        }
+        else if(corrected<startTime)
+        {
+            goto again;
+        }
+        else
+        {
+            *dts=corrected-startTime;
+        }
     }
     return true;
-
}
/**
         \fn audioCreateCopyStream
Index: avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.h
===================================================================
--- avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.h (revision 8341)
+++ avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.h (working copy)
@@ -58,6 +58,8 @@
         uint8_t         *videoBuffer;
         audioClock      **clocks;
         uint64_t        audioDelay;
+        int64_t         *padding;
+        uint64_t        *setTimeDts;
public:
                 muxerAvi();
         virtual ~muxerAvi();
Index: avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.cpp
===================================================================
--- avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.cpp (revision 8341)
+++ avidemux_plugins/ADM_muxers/muxerAvi/muxerAvi.cpp (working copy)
@@ -40,6 +40,8 @@
     audioPackets=NULL;
     videoBuffer=NULL;
     clocks=NULL;
+    padding=NULL;
+    setTimeDts=NULL;
};
/**
     \fn     muxerAVI
@@ -56,6 +58,9 @@
         delete [] clocks;
         clocks=NULL;
     }
+   
+    delete [] padding;
+    delete [] setTimeDts;
}

/**
@@ -79,9 +84,16 @@
         vStream=s;
         nbAStreams=nbAudioTrack;
         aStreams=a;
-        clocks=new audioClock*[nbAStreams];
+        clocks=new audioClock*[nbAStreams];       
+        padding=new int64_t[nbAStreams];
+        setTimeDts=new uint64_t[nbAStreams];
+       
         for(int i=0;i<nbAStreams;i++)
+        {
             clocks[i]=new audioClock(a[i]->getInfo()->frequency);
+            padding[i]=0;
+            setTimeDts[i]=0;
+        }
         
         return true;
}
@@ -121,12 +133,43 @@
                             aprintf("[Audio] Packet size %"PRIu32" sample:%"PRIu32" dts:%"PRIu64" target :%"PRIu64"\n",
                                             aPacket->sizeInBytes,aPacket->nbSamples,aPacket->dts,targetDts);
                             if(aPacket->dts!=ADM_NO_PTS)
-                                if( abs(aPacket->dts-clk->getTimeUs())>32000)
+                            {
+                                int64_t delta=aPacket->dts-clk->getTimeUs();
+                               
+                                if(delta>32000||delta<0)
                                 {
                                     ADM_warning("[AviMuxer] Audio skew!\n");
                                     clk->setTimeUs(aPacket->dts);
-#warning FIXME add padding
+                                    padding[audioIndex]+=delta-32000;
+                                   
+                                    if(setTimeDts[audioIndex])
+                                    {
+                                        setTimeDts[audioIndex]+=delta;
+                                    }
+                                    else if(padding[audioIndex]>32000)
+                                    {
+                                        setTimeDts[audioIndex]=aPacket->dts;
+                                    }
                                 }
+                            }
+                           
+                            if(padding[audioIndex]>=32000)
+                            {
+                                padding[audioIndex]-=32000;
+                            }
+                            else if(setTimeDts[audioIndex])
+                            {
+                                ADM_info("[AviMuxer] Rewinding audio stream\n");
+                                a->goToTime(setTimeDts[audioIndex]);
+                                clk->setTimeUs(setTimeDts[audioIndex]);
+                                setTimeDts[audioIndex]=0;
+                            }
+                           
                             aPacket->present=true;
                     }
                     // We now have a packet stored

KoolAidMan

Patch has been submitted to the patch gallery. It is slightly different from the patch above.