Ticket #7964: mythtv_smoothsync.6.patch

File mythtv_smoothsync.6.patch, 51.1 KB (added by Mark Spieth, 14 years ago)

same as 5 but made from lower in patch stack

  • mythtv/libs/libmyth/audiooutput.h

    commit 16d565b0b2ab5f059aa5ac655d8e852e1043ef79
    Author: Mark Spieth <mspieth@digivation.com.au>
    Date:   Tue Apr 27 07:51:51 2010 +1000
    
        smoother vsync with predictive frame skipping
    
    diff --git a/mythtv/libs/libmyth/audiooutput.h b/mythtv/libs/libmyth/audiooutput.h
    index e89147c..2889402 100644
    a b class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners 
    4343
    4444    // timecode is in milliseconds.
    4545    // Return true if all samples were written, false if none.
    46     virtual bool AddSamples(char *buffer, int samples, long long timecode) = 0;
    47     virtual bool AddSamples(char *buffers[], int samples, long long timecode) = 0;
     46    virtual bool AddSamples(char *buffer, int samples, int64_t timecode) = 0;
     47    virtual bool AddSamples(char *buffers[], int samples, int64_t timecode) = 0;
    4848
    49     virtual void SetTimecode(long long timecode) = 0;
     49    virtual void SetTimecode(int64_t timecode) = 0;
    5050    virtual bool IsPaused(void) const = 0;
    5151    virtual void Pause(bool paused) = 0;
    5252 
    5353    // Wait for all data to finish playing
    5454    virtual void Drain(void) = 0;
    5555
    56     virtual int GetAudiotime(void) = 0;
     56    virtual int64_t GetAudiotime(void) = 0;
    5757
    5858    /// report amount of audio buffered in milliseconds.
    59     virtual int GetAudioBufferedTime(void) { return 0; }
     59    virtual int64_t GetAudioBufferedTime(void) { return 0; }
    6060
    6161    virtual void SetSourceBitrate(int ) { }
    6262
  • mythtv/libs/libmyth/audiooutputbase.cpp

    diff --git a/mythtv/libs/libmyth/audiooutputbase.cpp b/mythtv/libs/libmyth/audiooutputbase.cpp
    index de6e0b0..f62eb06 100644
    a b  
    1919#define LOC QString("AO: ")
    2020#define LOC_ERR QString("AO, ERROR: ")
    2121
     22#define EFF_FACTOR_F  100000.0
     23#define EFF_FACTOR_I  100000
     24#define EFF_FACTOR_LL 100000LL
     25
    2226AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
    2327    // protected
    2428    effdsp(0),                  effdspstretched(0),
    AudioOutputBase::AudioOutputBase(const AudioSettings &settings) : 
    3135    audio_passthru_device(settings.GetPassthruDevice()),
    3236    audio_passthru(false),      audio_enc(false),
    3337    audio_reenc(false),         audio_stretchfactor(1.0f),
     38    eff_audio_stretchfactor(10000),
    3439
    3540    source(settings.source),    killaudio(false),
    3641
    void AudioOutputBase::SetStretchFactorLocked(float laudio_stretchfactor) 
    142147    if ((audio_stretchfactor != laudio_stretchfactor) ||  !pSoundStretch)
    143148    {
    144149        audio_stretchfactor = laudio_stretchfactor;
     150        eff_audio_stretchfactor = (int)(EFF_FACTOR_F * laudio_stretchfactor);
    145151        if (pSoundStretch)
    146152        {
    147153            VERBOSE(VB_GENERAL, LOC + QString("Changing time stretch to %1")
    void AudioOutputBase::Reset() 
    527533    gettimeofday(&audiotime_updated, NULL);
    528534}
    529535
    530 void AudioOutputBase::SetTimecode(long long timecode)
     536void AudioOutputBase::SetTimecode(int64_t timecode)
    531537{
    532538    QMutexLocker locker(&audio_buflock);
    533539    audbuf_timecode = timecode;
    534     samples_buffered = (long long)((timecode * effdsp) / 100000.0);
     540    samples_buffered = (int64_t)((timecode * effdsp) / EFF_FACTOR_I);
    535541}
    536542
    537543void AudioOutputBase::SetEffDsp(int dsprate)
    int AudioOutputBase::audiofree(bool use_lock) 
    573579       be is kAudioRingBufferSize - 1. */
    574580}
    575581
    576 int AudioOutputBase::GetAudiotime(void)
     582int64_t AudioOutputBase::GetAudiotime(void)
    577583{
    578584    /* Returns the current timecode of audio leaving the soundcard, based
    579585       on the 'audiotime' computed earlier, and the delay since it was computed.
    int AudioOutputBase::GetAudiotime(void) 
    583589       The reason is that computing 'audiotime' requires acquiring the audio
    584590       lock, which the video thread should not do. So, we call 'SetAudioTime()'
    585591       from the audio thread, and then call this from the video thread. */
    586     long long ret;
     592    int64_t ret;
    587593    struct timeval now;
    588594
    589595    if (audiotime == 0)
    int AudioOutputBase::GetAudiotime(void) 
    595601
    596602    ret = (now.tv_sec - audiotime_updated.tv_sec) * 1000;
    597603    ret += (now.tv_usec - audiotime_updated.tv_usec) / 1000;
    598     ret = (long long)(ret * audio_stretchfactor);
     604    ret = (int64_t)(ret * audio_stretchfactor);
    599605
    600606#if 1
    601607    VERBOSE(VB_AUDIO+VB_TIMESTAMP,
    int AudioOutputBase::GetAudiotime(void) 
    610616
    611617    ret += audiotime;
    612618
    613     return (int)ret;
     619    return ret;
    614620}
    615621
    616622void AudioOutputBase::SetAudiotime(void)
    void AudioOutputBase::SetAudiotime(void) 
    618624    if (audbuf_timecode == 0)
    619625        return;
    620626
    621     int soundcard_buffer = 0;
    622     int totalbuffer;
     627    int64_t soundcard_buffer = 0;
     628    int64_t totalsamples_stretched;
     629    int64_t totalsamples_unstretched = 0;
    623630
    624631    /* We want to calculate 'audiotime', which is the timestamp of the audio
    625632       which is leaving the sound card at this instant.
    void AudioOutputBase::SetAudiotime(void) 
    642649    QMutexLocker lock2(&avsync_lock);
    643650
    644651    soundcard_buffer = GetBufferedOnSoundcard(); // bytes
    645     totalbuffer = audiolen(false) + soundcard_buffer;
    646 
    647     // include algorithmic latencies
    648     if (pSoundStretch)
    649         totalbuffer += (int)((pSoundStretch->numUnprocessedSamples() *
    650                               audio_bytes_per_sample) / audio_stretchfactor);
     652    // major post-stretched buffer contents
     653    totalsamples_stretched = (audiolen(false) + soundcard_buffer) / audio_bytes_per_sample;
    651654
     655    // include algorithmic pre-stretch latencies
    652656    if (upmixer && needs_upmix)
    653         totalbuffer += upmixer->sampleLatency() * audio_bytes_per_sample;
     657        totalsamples_unstretched += upmixer->sampleLatency();
    654658
     659    if (pSoundStretch)
     660        totalsamples_unstretched += pSoundStretch->numUnprocessedSamples();
     661
     662    // include algorithmic post-stretch latencies
    655663    if (encoder)
    656          totalbuffer += encoder->Buffered();
     664        // the input buffered data is still in audio_bytes_per_sample format
     665        totalsamples_stretched += encoder->Buffered() / audio_bytes_per_sample;
    657666
    658     audiotime = audbuf_timecode - (int)(totalbuffer * 100000.0 /
    659                                    (audio_bytes_per_sample * effdspstretched));
     667    // timecode is the stretch adjusted version
     668    audiotime = audbuf_timecode - (int64_t)((totalsamples_unstretched * EFF_FACTOR_I +
     669                totalsamples_stretched * eff_audio_stretchfactor ) / effdsp );
    660670
    661671    gettimeofday(&audiotime_updated, NULL);
    662672#if 1
    663673    VERBOSE(VB_AUDIO+VB_TIMESTAMP,
    664674            QString("SetAudiotime set=%1.%2, audt=%3 atc=%4 "
    665                     "tb=%5 sb=%6 eds=%7 abps=%8 sf=%9")
     675                    "tss=%5 tsu=%6 sb=%7 eds=%8 abps=%9 sf=%10")
    666676            .arg(audiotime_updated.tv_sec).arg(audiotime_updated.tv_usec)
    667677            .arg(audiotime)
    668678            .arg(audbuf_timecode)
    669             .arg(totalbuffer)
     679            .arg(totalsamples_stretched)
     680            .arg(totalsamples_unstretched)
    670681            .arg(soundcard_buffer)
    671682            .arg(effdspstretched)
    672683            .arg(audio_bytes_per_sample)
    void AudioOutputBase::SetAudiotime(void) 
    674685#endif
    675686}
    676687
    677 int AudioOutputBase::GetAudioBufferedTime(void)
     688int64_t AudioOutputBase::GetAudioBufferedTime(void)
    678689{
    679690     return audbuf_timecode - GetAudiotime();
    680691}
    void AudioOutputBase::_AdjustVolume(AudioDataType *buffer, int len, bool music) 
    737748}
    738749
    739750bool AudioOutputBase::AddSamples(char *buffers[], int samples,
    740                                  long long timecode)
     751                                 int64_t timecode)
    741752{
    742753    // NOTE: This function is not threadsafe
    743754    int afree = audiofree(true);
    bool AudioOutputBase::AddSamples(char *buffers[], int samples, 
    805816    return true;
    806817}
    807818
    808 bool AudioOutputBase::AddSamples(char *buffer, int samples, long long timecode)
     819bool AudioOutputBase::AddSamples(char *buffer, int samples, int64_t timecode)
    809820{
    810821    // NOTE: This function is not threadsafe
    811822
    void *AudioOutputBase::_MonoToStereo(AudioDataType *s1, AudioDataType *s2, int s 
    936947    return s2;
    937948}
    938949
    939 void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int samples,
    940                                   long long timecode)
     950void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int in_samples,
     951                                  int64_t timecode)
    941952{
    942953    int len; // = samples * audio_bytes_per_sample;
    943954    int audio_bytes = audio_bits / 8;
    944955    int org_waud = waud;
     956    int samples = in_samples;
    945957
    946958    int afree = audiofree(false);
    947959
    void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int samples, 
    980992        int out_samples = 0;
    981993        org_waud = waud;
    982994        int step = (interleaved)?source_audio_channels:1;
    983        
     995
    984996        for (int itemp = 0; itemp < samples; )
    985997        {
    986998            if (audio_bytes == 2)
    void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int samples, 
    10651077        }
    10661078    }
    10671079
    1068     if (samples <= 0)
    1069         return;
    1070        
    1071     if (pSoundStretch)
     1080    if (samples > 0)
    10721081    {
    1073         // does not change the timecode, only the number of samples
    1074         // back to orig pos
    1075         org_waud = waud;
    1076         int bdiff = kAudioRingBufferSize - org_waud;
    1077         int nSamplesToEnd = bdiff/abps;
    1078         if (bdiff < len)
    1079         {
    1080             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
    1081                                       (audiobuffer +
    1082                                        org_waud), nSamplesToEnd);
    1083             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer,
    1084                                       (len - bdiff) / abps);
    1085         }
    1086         else
    1087         {
    1088             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
    1089                                       (audiobuffer + org_waud),
    1090                                       len / abps);
    1091         }
    10921082
    1093         int nSamples = pSoundStretch->numSamples();
    1094         len = WaitForFreeSpace(nSamples);
    1095        
    1096         while ((nSamples = pSoundStretch->numSamples()))
     1083        if (pSoundStretch)
    10971084        {
    1098             if (nSamples > nSamplesToEnd)
    1099                 nSamples = nSamplesToEnd;
    1100            
    1101             nSamples = pSoundStretch->receiveSamples(
    1102                 (soundtouch::SAMPLETYPE*)
    1103                 (audiobuffer + org_waud), nSamples
    1104             );
    1105            
    1106             if (nSamples == nSamplesToEnd) {
    1107                 org_waud = 0;
    1108                 nSamplesToEnd = kAudioRingBufferSize/abps;
     1085            // does not change the timecode, only the number of samples
     1086            // back to orig pos
     1087            org_waud = waud;
     1088            int bdiff = kAudioRingBufferSize - org_waud;
     1089            int nSamplesToEnd = bdiff/abps;
     1090            if (bdiff < len)
     1091            {
     1092                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
     1093                        (audiobuffer +
     1094                         org_waud), nSamplesToEnd);
     1095                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer,
     1096                        (len - bdiff) / abps);
    11091097            }
    1110             else {
    1111                 org_waud += nSamples * abps;
    1112                 nSamplesToEnd -= nSamples;
     1098            else
     1099            {
     1100                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
     1101                        (audiobuffer + org_waud),
     1102                        len / abps);
    11131103            }
    1114         }
    1115     }
    11161104
    1117     if (internal_vol && SWVolume())
    1118     {
    1119         int bdiff = kAudioRingBufferSize - waud;
    1120         bool music = (timecode < 1);
     1105            int nSamples = pSoundStretch->numSamples();
     1106            len = WaitForFreeSpace(nSamples);
    11211107
    1122         if (bdiff < len)
    1123         {
    1124             AdjustVolume(audiobuffer + waud, bdiff, music);
    1125             AdjustVolume(audiobuffer, len - bdiff, music);
    1126         }
    1127         else
    1128             AdjustVolume(audiobuffer + waud, len, music);
    1129     }
     1108            while ((nSamples = pSoundStretch->numSamples()))
     1109            {
     1110                if (nSamples > nSamplesToEnd)
     1111                    nSamples = nSamplesToEnd;
    11301112
    1131     // Encode to AC-3?
    1132     if (encoder)
    1133     {
    1134         org_waud = waud;
    1135         int bdiff = kAudioRingBufferSize - org_waud;
    1136         int to_get = 0;
     1113                nSamples = pSoundStretch->receiveSamples(
     1114                        (soundtouch::SAMPLETYPE*)
     1115                        (audiobuffer + org_waud), nSamples
     1116                        );
    11371117
    1138         if (bdiff < len)
     1118                if (nSamples == nSamplesToEnd) {
     1119                    org_waud = 0;
     1120                    nSamplesToEnd = kAudioRingBufferSize/abps;
     1121                }
     1122                else {
     1123                    org_waud += nSamples * abps;
     1124                    nSamplesToEnd -= nSamples;
     1125                }
     1126            }
     1127        }
     1128
     1129        if (internal_vol && SWVolume())
    11391130        {
    1140             encoder->Encode(audiobuffer + org_waud, bdiff);
    1141             to_get = encoder->Encode(audiobuffer, len - bdiff);
     1131            int bdiff = kAudioRingBufferSize - waud;
     1132            bool music = (timecode < 1);
     1133
     1134            if (bdiff < len)
     1135            {
     1136                AdjustVolume(audiobuffer + waud, bdiff, music);
     1137                AdjustVolume(audiobuffer, len - bdiff, music);
     1138            }
     1139            else
     1140                AdjustVolume(audiobuffer + waud, len, music);
    11421141        }
    1143         else
    1144             to_get = encoder->Encode(audiobuffer + org_waud, len);
    11451142
    1146         if (to_get > 0)
     1143        // Encode to AC-3?
     1144        if (encoder)
    11471145        {
    1148             if (to_get >= bdiff)
     1146            org_waud = waud;
     1147            int bdiff = kAudioRingBufferSize - org_waud;
     1148            int to_get = 0;
     1149
     1150            if (bdiff < len)
    11491151            {
    1150                 encoder->GetFrames(audiobuffer + org_waud, bdiff);
    1151                 to_get -= bdiff;
    1152                 org_waud = 0;
     1152                encoder->Encode(audiobuffer + org_waud, bdiff);
     1153                to_get = encoder->Encode(audiobuffer, len - bdiff);
    11531154            }
    1154             if (to_get > 0)
    1155                 encoder->GetFrames(audiobuffer + org_waud, to_get);
     1155            else
     1156                to_get = encoder->Encode(audiobuffer + org_waud, len);
     1157
     1158            if (to_get > 0)
     1159            {
     1160                if (to_get >= bdiff)
     1161                {
     1162                    encoder->GetFrames(audiobuffer + org_waud, bdiff);
     1163                    to_get -= bdiff;
     1164                    org_waud = 0;
     1165                }
     1166                if (to_get > 0)
     1167                    encoder->GetFrames(audiobuffer + org_waud, to_get);
    11561168
    1157             org_waud += to_get;
     1169                org_waud += to_get;
     1170            }
    11581171        }
    1159     }
    11601172
    1161     waud = org_waud;
    1162     lastaudiolen = audiolen(false);
     1173        waud = org_waud;
     1174        lastaudiolen = audiolen(false);
     1175    }
    11631176
    11641177    if (timecode < 0)
    11651178        // mythmusic doesn't give timestamps..
    1166         timecode = (int)((samples_buffered * 100000.0) / effdsp);
     1179        timecode = (int64_t)((samples_buffered * EFF_FACTOR_I) / effdsp);
    11671180
    1168     samples_buffered += samples;
     1181    samples_buffered += in_samples;
    11691182
    11701183    /* we want the time at the end -- but the file format stores
    11711184       time at the start of the chunk. */
    11721185    // even with timestretch, timecode is still calculated from original
    11731186    // sample count
    1174     audbuf_timecode = timecode + (int)((samples * 100000.0) / effdsp);
     1187    audbuf_timecode = timecode + (int64_t)((in_samples * EFF_FACTOR_I) / effdsp);
    11751188}
    11761189
    11771190void AudioOutputBase::Status()
    void AudioOutputBase::OutputAudioLoop(void) 
    12081221    unsigned char *zeros    = new unsigned char[fragment_size];
    12091222    unsigned char *fragment = new unsigned char[fragment_size];
    12101223
     1224    // to reduce startup latency, write silence in 8ms chunks
     1225    int zero_fragment_size = (int)(0.008*audio_samplerate/audio_channels);
     1226    zero_fragment_size *= audio_channels * audio_bits / 16;   // make sure its a multiple of audio_channels
     1227    if (zero_fragment_size > fragment_size)
     1228        zero_fragment_size = fragment_size;
     1229
    12111230    bzero(zeros, fragment_size);
    12121231    last_space_on_soundcard = 0;
    12131232
    void AudioOutputBase::OutputAudioLoop(void) 
    12401259
    12411260            // only send zeros if card doesn't already have at least one
    12421261            // fragment of zeros -dag
    1243             if (fragment_size >= soundcard_buffer_size - space_on_soundcard)
     1262            if (zero_fragment_size >= soundcard_buffer_size - space_on_soundcard)
    12441263            {
    1245                 if (fragment_size <= space_on_soundcard)
     1264                if (zero_fragment_size <= space_on_soundcard)
    12461265                {
    1247                     WriteAudio(zeros, fragment_size);
     1266                    WriteAudio(zeros, zero_fragment_size);
    12481267                }
    12491268                else
    12501269                {
    void AudioOutputBase::OutputAudioLoop(void) 
    12521271                    VERBOSE(VB_AUDIO+VB_TIMESTAMP, LOC +
    12531272                            QString("waiting for space on soundcard "
    12541273                                    "to write zeros: have %1 need %2")
    1255                             .arg(space_on_soundcard).arg(fragment_size));
     1274                            .arg(space_on_soundcard).arg(zero_fragment_size));
    12561275                    usleep(5000);
    12571276                }
    12581277            }
  • mythtv/libs/libmyth/audiooutputbase.h

    diff --git a/mythtv/libs/libmyth/audiooutputbase.h b/mythtv/libs/libmyth/audiooutputbase.h
    index 8d9e86b..5778694 100644
    a b class AudioOutputBase : public AudioOutput, public QThread 
    5151    int GetSWVolume(void);
    5252
    5353    // timecode is in milliseconds.
    54     virtual bool AddSamples(char *buffer, int samples, long long timecode);
    55     virtual bool AddSamples(char *buffers[], int samples, long long timecode);
     54    virtual bool AddSamples(char *buffer, int samples, int64_t timecode);
     55    virtual bool AddSamples(char *buffers[], int samples, int64_t timecode);
    5656
    57     virtual void SetTimecode(long long timecode);
     57    virtual void SetTimecode(int64_t timecode);
    5858    virtual bool IsPaused(void) const { return audio_actually_paused; }
    5959    virtual void Pause(bool paused);
    6060
    6161    // Wait for all data to finish playing
    6262    virtual void Drain(void);
    6363
    64     virtual int GetAudiotime(void);
    65     virtual int GetAudioBufferedTime(void);
     64    virtual int64_t GetAudiotime(void);
     65    virtual int64_t GetAudioBufferedTime(void);
    6666
    6767    // Send output events showing current progress
    6868    virtual void Status(void);
    class AudioOutputBase : public AudioOutput, public QThread 
    100100
    101101    int GetAudioData(unsigned char *buffer, int buf_size, bool fill_buffer);
    102102
    103     void _AddSamples(void *buffer, bool interleaved, int samples, long long timecode);
     103    void _AddSamples(void *buffer, bool interleaved, int samples, int64_t timecode);
    104104
    105105    void OutputAudioLoop(void);
    106106
    class AudioOutputBase : public AudioOutput, public QThread 
    117117
    118118    void SetStretchFactorLocked(float factor);
    119119
    120     int GetBaseAudioTime()                    const { return audiotime;       }
    121     int GetBaseAudBufTimeCode()               const { return audbuf_timecode; }
     120    int64_t GetBaseAudioTime()                const { return audiotime;       }
     121    int64_t GetBaseAudBufTimeCode()           const { return audbuf_timecode; }
    122122    soundtouch::SoundTouch *GetSoundStretch() const { return pSoundStretch;   }
    123     void SetBaseAudioTime(const int inAudioTime) { audiotime = inAudioTime; }
     123    void SetBaseAudioTime(const int64_t inAudioTime) { audiotime = inAudioTime; }
    124124
    125125  protected:
    126126    int effdsp; // from the recorded stream
    class AudioOutputBase : public AudioOutput, public QThread 
    143143    bool audio_reenc;
    144144
    145145    float audio_stretchfactor;
     146    int  eff_audio_stretchfactor;     // scaled to 10000 as effdsp is
    146147    AudioOutputSource source;
    147148
    148149    bool killaudio;
    class AudioOutputBase : public AudioOutput, public QThread 
    186187    bool blocking; // do AddSamples calls block?
    187188
    188189    int lastaudiolen;
    189     long long samples_buffered;
     190    int64_t samples_buffered;
    190191
    191192    bool audio_thread_exists;
    192193
    class AudioOutputBase : public AudioOutput, public QThread 
    203204    QMutex avsync_lock;
    204205
    205206    /// timecode of audio leaving the soundcard (same units as timecodes)
    206     long long audiotime;
     207    int64_t audiotime;
    207208    struct timeval audiotime_updated; // ... which was last updated at this time
    208209
    209210    /* Audio circular buffer */
    210211    int raud, waud;     /* read and write positions */
    211212    /// timecode of audio most recently placed into buffer
    212     long long audbuf_timecode;
     213    int64_t audbuf_timecode;
    213214
    214215    int numlowbuffer;
    215216
  • mythtv/libs/libmythtv/NuppelVideoPlayer.cpp

    diff --git a/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp b/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
    index cf1e690..bcda6ea 100644
    a b NuppelVideoPlayer::NuppelVideoPlayer(bool muted) 
    206206      videosync(NULL),              delay(0),
    207207      vsynctol(30/4),               avsync_delay(0),
    208208      avsync_adjustment(0),         avsync_avg(0),
    209       avsync_oldavg(0),             refreshrate(0),
     209      avsync_oldavg(0),             
     210      avsync_predictor(0),          avsync_predictor_enabled(false),
     211      refreshrate(0),
    210212      lastsync(false),              m_playing_slower(false),
    211213      m_stored_audio_stretchfactor(1.0),
    212214      audio_paused(false),
    NuppelVideoPlayer::NuppelVideoPlayer(bool muted) 
    238240    db_prefer708     = gContext->GetNumSetting("Prefer708Captions", 1);
    239241    autocommercialskip = (CommSkipMode)
    240242        gContext->GetNumSetting("AutoCommercialSkip", kCommSkipOff);
     243    usesmoothsync    = gContext->GetNumSetting("UseSmoothSync", 1) != 0;
    241244
    242245    lastIgnoredManualSkip = QDateTime::currentDateTime().addSecs(-10);
    243246
    void NuppelVideoPlayer::SetVideoParams(int width, int height, double fps, 
    11181121        video_frame_rate = fps;
    11191122        float temp_speed = (play_speed == 0.0f) ?
    11201123            audio_stretchfactor : play_speed;
    1121         frame_interval = (int)(1000000.0f / video_frame_rate / temp_speed);
     1124        SetFrameInterval(kScan_Progressive, 1.0 / (video_frame_rate * temp_speed));
    11221125    }
    11231126
    11241127    if (videoOutput)
    float NuppelVideoPlayer::WarpFactor(void) 
    23102313    return divergence;
    23112314}
    23122315
     2316void NuppelVideoPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
     2317{
     2318    frame_interval = (int)(1000000.0f * frame_period + 0.5f);
     2319    avsync_predictor = 0;
     2320    avsync_predictor_enabled = false;
     2321
     2322    VERBOSE(VB_PLAYBACK, LOC + QString("SetFrameInterval ps:%1 scan:%2 usesmoothsync:%3")
     2323            .arg(play_speed).arg(scan).arg(usesmoothsync)
     2324           );
     2325    //if (play_speed <= 1 || play_speed > 2 || scan != kScan_Progressive || !usesmoothsync)
     2326    if (play_speed < 1 || play_speed > 2 || refreshrate <= 0 || !usesmoothsync)
     2327        return;
     2328
     2329    avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) < refreshrate);
     2330}
     2331
     2332void NuppelVideoPlayer::ResetAVSync(void)
     2333{
     2334    avsync_avg = 0;
     2335    avsync_oldavg = 0;
     2336    avsync_predictor = 0;
     2337    prevtc = 0;
     2338    warpfactor = 1.0f;
     2339    warpfactor_avg = 1.0f;
     2340    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V sync reset");
     2341}
     2342
    23132343void NuppelVideoPlayer::InitAVSync(void)
    23142344{
    23152345    videosync->Start();
    void NuppelVideoPlayer::InitAVSync(void) 
    23312361        VERBOSE(VB_GENERAL, msg);
    23322362        msg = QString("Refresh rate: %1, frame interval: %2")
    23332363                       .arg(refreshrate).arg(frame_interval);
    2334         VERBOSE(VB_PLAYBACK, msg);
     2364        VERBOSE(VB_PLAYBACK, LOC + msg);
     2365
     2366        SetFrameInterval(m_scan, 1.0 / (video_frame_rate * play_speed));
    23352367
    23362368        // try to get preferential scheduling, but ignore if we fail to.
    23372369        myth_nice(-19);
    23382370    }
    23392371}
    23402372
     2373int64_t NuppelVideoPlayer::AVSyncGetAudiotime(void)
     2374{
     2375    int64_t currentaudiotime = 0;
     2376    audio_lock.lock();
     2377    if (audioOutput && normal_speed)
     2378    {
     2379        currentaudiotime = audioOutput->GetAudiotime();
     2380    }
     2381    audio_lock.unlock();
     2382    return currentaudiotime;
     2383}
     2384
    23412385void NuppelVideoPlayer::AVSync(void)
    23422386{
    23432387    float diverge = 0.0f;
     2388    int vsync_delay_clock = 0;
     2389    int64_t currentaudiotime = 0;
     2390
    23442391    // attempt to reduce fps for standalone PIP
    23452392    if (player_ctx->IsPIP() && framesPlayed % 2)
    23462393    {
    void NuppelVideoPlayer::AVSync(void) 
    23802427        ps = kScan_Progressive;
    23812428
    23822429    bool dropframe = false;
     2430    QString dbg;
     2431
     2432    if (avsync_predictor_enabled)
     2433    {
     2434        avsync_predictor += frame_interval;
     2435        if (avsync_predictor >= refreshrate)
     2436        {
     2437            int refreshperiodsinframe = avsync_predictor/refreshrate;
     2438            avsync_predictor -= refreshrate * refreshperiodsinframe;
     2439        }
     2440        else
     2441        {
     2442            dropframe = true;
     2443            dbg = "A/V predict drop frame, ";
     2444        }
     2445    }
     2446
    23832447    if (diverge < -MAXDIVERGE)
    23842448    {
    23852449        dropframe = true;
    23862450        // If video is way behind of audio, adjust for it...
    2387         QString dbg = QString("Video is %1 frames behind audio (too slow), ")
     2451        dbg = QString("Video is %1 frames behind audio (too slow), ")
    23882452            .arg(-diverge);
     2453    }
    23892454
     2455    if (dropframe)
     2456    {
    23902457        // Reset A/V Sync
    23912458        lastsync = true;
    23922459
     2460        currentaudiotime = AVSyncGetAudiotime();
     2461
    23932462        if (buffer && !using_null_videoout &&
    23942463            videoOutput->hasHWAcceleration() &&
    23952464           !videoOutput->IsSyncLocked())
    void NuppelVideoPlayer::AVSync(void) 
    24142483        if (buffer)
    24152484            videoOutput->PrepareFrame(buffer, ps);
    24162485
    2417         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
     2486        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("AVSync waitforframe %1 %2")
    24182487                .arg(avsync_adjustment).arg(m_double_framerate));
    2419         videosync->WaitForFrame(avsync_adjustment + repeat_delay);
    2420         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
     2488        vsync_delay_clock = videosync->WaitForFrame(avsync_adjustment + repeat_delay);
     2489        currentaudiotime = AVSyncGetAudiotime();
     2490        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + "AVSync show");
    24212491        if (!resetvideo)
    24222492            videoOutput->Show(ps);
    24232493
    24242494        if (videoOutput->IsErrored())
    24252495        {
    2426             VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
     2496            VERBOSE(VB_IMPORTANT, LOC + "Error condition detected "
    24272497                    "in videoOutput after Show(), aborting playback.");
    24282498            SetErrored(QObject::tr("Serious error detected in Video Output"));
    24292499            return;
    void NuppelVideoPlayer::AVSync(void) 
    24592529            // Display the second field
    24602530            videosync->AdvanceTrigger();
    24612531#ifdef NEW_AVSYNC
    2462             videosync->WaitForFrame(avsync_adjustment);
     2532            vsync_delay_clock = videosync->WaitForFrame(avsync_adjustment);
    24632533#else
    2464             videosync->WaitForFrame(0);
     2534            vsync_delay_clock = videosync->WaitForFrame(0);
    24652535#endif
    24662536            if (!resetvideo)
    24672537            {
    void NuppelVideoPlayer::AVSync(void) 
    24722542        repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
    24732543
    24742544        if (repeat_delay)
    2475             VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
     2545            VERBOSE(VB_TIMESTAMP, LOC + QString("A/V repeat_pict, adding %1 repeat "
    24762546                    "delay").arg(repeat_delay));
    24772547    }
    24782548    else
    24792549    {
    2480         videosync->WaitForFrame(0);
     2550        vsync_delay_clock = videosync->WaitForFrame(0);
     2551        currentaudiotime = AVSyncGetAudiotime();
    24812552    }
    24822553
    24832554    if (output_jmeter && output_jmeter->RecordCycleTime())
    24842555    {
    2485         VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString("A/V avsync_delay: %1, "
     2556        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V avsync_delay: %1, "
    24862557                "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
    24872558                .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
    24882559                .arg(warpfactor).arg(warpfactor_avg));
    void NuppelVideoPlayer::AVSync(void) 
    24982569        // by cutting the frame rate in half for the length of this frame
    24992570
    25002571#ifdef NEW_AVSYNC
    2501         avsync_adjustment = refreshrate;
     2572        //avsync_adjustment = refreshrate;
     2573        avsync_adjustment = frame_interval;
     2574        //avsync_adjustment = frame_interval*(((int)MAXDIVERGE)-1);
    25022575#else
    25032576        avsync_adjustment = frame_interval;
    25042577#endif
    void NuppelVideoPlayer::AVSync(void) 
    25082581                        "\t\t\tdoubling video frame interval to slow down.").arg(diverge));
    25092582    }
    25102583
    2511     audio_lock.lock();
    25122584    if (audioOutput && normal_speed)
    25132585    {
    2514         long long currentaudiotime = audioOutput->GetAudiotime();
    2515         audio_lock.unlock();
    25162586#if 0
    2517         VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString(
     2587        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString(
    25182588                    "A/V timecodes audio %1 video %2 frameinterval %3 "
    2519                     "avdel %4 avg %5 tcoffset %6")
     2589                    "avdel %4 avg %5 tcoffset %6"
     2590                    " avp %7 avpen %8"
     2591                    " avdc %9"
     2592                    )
    25202593                .arg(currentaudiotime)
    25212594                .arg(buffer->timecode)
    25222595                .arg(frame_interval)
    2523                 .arg(buffer->timecode - currentaudiotime)
     2596                .arg(buffer->timecode - currentaudiotime - (int)(vsync_delay_clock*audio_stretchfactor+500)/1000)
    25242597                .arg(avsync_avg)
    25252598                .arg(tc_wrap[TC_AUDIO])
     2599                .arg(avsync_predictor)
     2600                .arg(avsync_predictor_enabled)
     2601                .arg(vsync_delay_clock)
    25262602                 );
    25272603#endif
    25282604        if (currentaudiotime != 0 && buffer->timecode != 0)
    25292605        { // currentaudiotime == 0 after a seek
    25302606            // The time at the start of this frame (ie, now) is given by
    25312607            // last->timecode
    2532             int delta = (int)((buffer->timecode - prevtc)/play_speed) - (frame_interval / 1000);
    2533             prevtc = buffer->timecode;
    2534             //cerr << delta << " ";
    2535 
    2536             // If the timecode is off by a frame (dropped frame) wait to sync
    2537             if (delta > (int) frame_interval / 1200 &&
    2538                 delta < (int) frame_interval / 1000 * 3 &&
    2539                 prevrp == 0)
     2608            if (prevtc != 0)
    25402609            {
    2541                 //cerr << "+ ";
    2542                 videosync->AdvanceTrigger();
    2543                 if (m_double_framerate)
     2610                int delta = (int)((buffer->timecode - prevtc)/play_speed) - (frame_interval / 1000);
     2611                // If the timecode is off by a frame (dropped frame) wait to sync
     2612                if (delta > (int) frame_interval / 1200 &&
     2613                    delta < (int) frame_interval / 1000 * 3 &&
     2614                    prevrp == 0)
     2615                {
     2616                    //cerr << "+ ";
     2617                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V delay %1").arg(delta));
    25442618                    videosync->AdvanceTrigger();
     2619                    if (m_double_framerate)
     2620                        videosync->AdvanceTrigger();
     2621                }
    25452622            }
     2623            prevtc = buffer->timecode;
    25462624            prevrp = buffer->repeat_pict;
    25472625
    2548             avsync_delay = (buffer->timecode - currentaudiotime) * 1000;//usec
     2626            avsync_delay = (buffer->timecode - currentaudiotime) * 1000 - (int)(vsync_delay_clock*audio_stretchfactor);  //usec
    25492627            // prevents major jitter when pts resets during dvd title
    25502628            if (avsync_delay > 2000000 && player_ctx->buffer->isDVD())
    25512629                avsync_delay = 90000;
    void NuppelVideoPlayer::AVSync(void) 
    25552633               the video by one interlaced field (1/2 frame) */
    25562634            if (!lastsync)
    25572635            {
    2558                 if (avsync_avg > frame_interval * 3 / 2)
     2636                if (avsync_delay > refreshrate)
    25592637                {
    2560                     avsync_adjustment = refreshrate;
    2561                     lastsync = true;
     2638                    avsync_adjustment += refreshrate;
     2639                    //lastsync = true;
     2640                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high extend");
    25622641                }
    2563                 else if (avsync_avg < 0 - frame_interval * 3 / 2)
     2642                else if (avsync_delay < 0 - refreshrate)
    25642643                {
    2565                     avsync_adjustment = -refreshrate;
    2566                     lastsync = true;
     2644                    avsync_adjustment -= refreshrate;
     2645                    //lastsync = true;
     2646                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high skip");
    25672647                }
    25682648            }
    25692649            else
    void NuppelVideoPlayer::AVSync(void) 
    25712651        }
    25722652        else
    25732653        {
    2574             avsync_avg = 0;
    2575             avsync_oldavg = 0;
     2654            ResetAVSync();
    25762655        }
    25772656    }
    25782657    else
    2579         audio_lock.unlock();
     2658    {
     2659        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V no sync proc ns:%1 ao:%2").arg(normal_speed).arg(audioOutput != NULL));
     2660    }
    25802661}
    25812662
    25822663void NuppelVideoPlayer::DisplayPauseFrame(void)
    void NuppelVideoPlayer::DoPause(void) 
    42104291    }
    42114292
    42124293    float temp_speed = audio_stretchfactor;
    4213     frame_interval = (int)(1000000.0 * ffrew_skip / video_frame_rate / temp_speed);
     4294    SetFrameInterval(m_scan, ffrew_skip / (video_frame_rate * temp_speed));
    42144295    VERBOSE(VB_PLAYBACK, QString("rate: %1 speed: %2 skip: %3 = interval %4")
    42154296                                 .arg(video_frame_rate).arg(temp_speed)
    42164297                                 .arg(ffrew_skip).arg(frame_interval));
    void NuppelVideoPlayer::DoPlay(void) 
    42724353        ClearAfterSeek();
    42734354    }
    42744355
    4275     frame_interval = (int) (1000000.0f * ffrew_skip / video_frame_rate /
    4276                             play_speed);
     4356    SetFrameInterval(m_scan, ffrew_skip / (video_frame_rate * play_speed));
    42774357
    42784358    VERBOSE(VB_PLAYBACK, LOC + "DoPlay: " +
    42794359            QString("rate: %1 speed: %2 skip: %3 => new interval %4")
    void NuppelVideoPlayer::ClearAfterSeek(bool clearvideobuffers) 
    46714751        savedAudioTimecodeOffset = 0;
    46724752    }
    46734753
     4754    ResetAVSync();
    46744755    SetPrebuffering(true);
    46754756    audio_lock.lock();
    46764757    if (audioOutput)
  • mythtv/libs/libmythtv/NuppelVideoPlayer.h

    diff --git a/mythtv/libs/libmythtv/NuppelVideoPlayer.h b/mythtv/libs/libmythtv/NuppelVideoPlayer.h
    index 33854f5..85e533a 100644
    a b class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader 
    511511    float WarpFactor(void);
    512512    void  WrapTimecode(long long &timecode, TCTypes tc_type);
    513513    void  InitAVSync(void);
     514    void  ResetAVSync(void);
     515    int64_t AVSyncGetAudiotime(void);
     516    void  SetFrameInterval(FrameScanType scan, double speed);
    514517    void  AVSync(void);
    515518    void  FallbackDeint(void);
    516519    void  CheckExtraAudioDecode(void);
    class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader 
    797800    int        avsync_adjustment;
    798801    int        avsync_avg;
    799802    int        avsync_oldavg;
     803    bool       usesmoothsync;
     804    int        avsync_predictor;
     805    bool       avsync_predictor_enabled;
    800806    int        refreshrate;
    801807    bool       lastsync;
    802808    bool       m_playing_slower;
  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index edf3d59..f4d6f9c 100644
    a b AvFormatDecoder::AvFormatDecoder(NuppelVideoPlayer *parent, 
    481481      start_code_state(0xffffffff),
    482482      lastvpts(0),                  lastapts(0),
    483483      lastccptsu(0),
     484      firstvpts(0),                 firstvptsinuse(false),
    484485      using_null_videoout(use_null_videoout),
    485486      video_codec_id(kCodec_NONE),
    486487      no_hardware_decoders(no_hardware_decode),
    void AvFormatDecoder::SeekReset(long long newKey, uint skipFrames, 
    929930        if (decoded_video_frame)
    930931            GetNVP()->DiscardVideoFrame(decoded_video_frame);
    931932    }
     933
     934    if (doflush)
     935    {
     936        firstvpts = 0;
     937        firstvptsinuse = true;
     938    }
    932939}
    933940
    934941void AvFormatDecoder::Reset(bool reset_video_data, bool seek_reset)
    void AvFormatDecoder::MpegPreProcessPkt(AVStream *stream, AVPacket *pkt) 
    29222929
    29232930                gopset = false;
    29242931                prevgoppos = 0;
     2932                firstvpts =
    29252933                lastapts = lastvpts = lastccptsu = 0;
     2934                firstvptsinuse = true;
    29262935
    29272936                // fps debugging info
    29282937                float avFPS = normalized_fps(stream, context);
    bool AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt) 
    30323041
    30333042            gopset = false;
    30343043            prevgoppos = 0;
     3044            firstvpts =
    30353045            lastapts = lastvpts = lastccptsu = 0;
     3046            firstvptsinuse = true;
    30363047
    30373048            // fps debugging info
    30383049            float avFPS = normalized_fps(stream, context);
    bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt) 
    32543265    framesPlayed++;
    32553266
    32563267    lastvpts = temppts;
     3268    if (!firstvpts && firstvptsinuse)
     3269        firstvpts = temppts;
    32573270
    32583271    return true;
    32593272}
    bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt, 
    40224035                skipaudio = false;
    40234036        }
    40244037
     4038        // skip any audio frames preceding first video frame
     4039        if (firstvptsinuse && firstvpts && (lastapts < firstvpts))
     4040        {
     4041            VERBOSE(VB_PLAYBACK+VB_TIMESTAMP,
     4042                LOC + QString("discarding early audio timecode %1 %2 %3")
     4043                .arg(pkt->pts).arg(pkt->dts).arg(lastapts));
     4044            break;
     4045        }
     4046        firstvptsinuse = false;
     4047
    40254048        avcodeclock->lock();
    40264049        data_size = 0;
    40274050
  • mythtv/libs/libmythtv/avformatdecoder.h

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
    index 90b8f58..f48bc18 100644
    a b class AvFormatDecoder : public DecoderBase 
    262262    long long lastvpts;
    263263    long long lastapts;
    264264    long long lastccptsu;
     265    long long firstvpts;
     266    bool      firstvptsinuse;
    265267
    266268    bool using_null_videoout;
    267269    MythCodecID video_codec_id;
  • mythtv/libs/libmythtv/vsync.cpp

    diff --git a/mythtv/libs/libmythtv/vsync.cpp b/mythtv/libs/libmythtv/vsync.cpp
    index 060402d..4d6a2d2 100644
    a b VideoSync::VideoSync(VideoOutput *video_output, 
    123123                     bool halve_frame_interval) :
    124124    m_video_output(video_output),   m_frame_interval(frameint),
    125125    m_refresh_interval(refreshint), m_interlaced(halve_frame_interval),
    126     m_delay(-1)
     126    m_nexttrigger(0),
     127    m_delay(-1),
     128    m_synchronous(false)
    127129{
    128     bzero(&m_nexttrigger, sizeof(m_nexttrigger));
    129130
    130131    int tolerance = m_refresh_interval / 200;
    131132    if (m_interlaced && m_refresh_interval > ((m_frame_interval/2) + tolerance))
    VideoSync::VideoSync(VideoOutput *video_output, 
    136137
    137138void VideoSync::Start(void)
    138139{
    139     gettimeofday(&m_nexttrigger, NULL); // now
     140    struct timeval now_tv;
     141    gettimeofday(&now_tv, NULL); // now
     142    m_nexttrigger = now_tv.tv_sec * 1000000LL + now_tv.tv_usec;
    140143}
    141144
    142145/** \fn VideoSync::SetFrameInterval(int fr, bool intr)
    void VideoSync::SetFrameInterval(int fr, bool intr) 
    147150    m_frame_interval = fr;
    148151    m_interlaced = intr;
    149152    int tolerance = m_refresh_interval / 200;
     153    double sync_factor = fr * 2.0f / intr;
     154    sync_factor = sync_factor - round(sync_factor);
     155    m_synchronous = (sync_factor >= -0.005) && (sync_factor <= 0.005);
    150156    if (m_interlaced && m_refresh_interval > ((m_frame_interval/2) + tolerance))
    151157        m_interlaced = false; // can't display both fields at 2x rate
    152158
    153     VERBOSE(VB_PLAYBACK, QString("Set video sync frame interval to %1")
    154                                  .arg(m_frame_interval));
    155 }
    156 
    157 void VideoSync::OffsetTimeval(struct timeval& tv, int offset)
    158 {
    159     tv.tv_usec += offset;
    160     while (tv.tv_usec > 999999)
    161     {
    162         tv.tv_sec++;
    163         tv.tv_usec -= 1000000;
    164     }
    165     while (tv.tv_usec < 0)
    166     {
    167         tv.tv_sec--;
    168         tv.tv_usec += 1000000;
    169     }
     159    VERBOSE(VB_PLAYBACK, QString("Set video sync frame interval to %1 (synced:%2)")
     160                                 .arg(m_frame_interval).arg(m_synchronous));
    170161}
    171162
    172163/** \fn VideoSync::UpdateNexttrigger()
    void VideoSync::UpdateNexttrigger() 
    179170    // Offset by frame interval -- if interlaced, only delay by half
    180171    // frame interval
    181172    if (m_interlaced)
    182         OffsetTimeval(m_nexttrigger, m_frame_interval/2);
     173        m_nexttrigger += m_frame_interval/2;
    183174    else
    184         OffsetTimeval(m_nexttrigger, m_frame_interval);
     175        m_nexttrigger += m_frame_interval;
    185176}
    186177
    187178/** \fn VideoSync::CalcDelay()
    void VideoSync::UpdateNexttrigger() 
    197188 */
    198189int VideoSync::CalcDelay()
    199190{
    200     struct timeval now;
    201     gettimeofday(&now, NULL);
     191    struct timeval now_tv;
     192    gettimeofday(&now_tv, NULL);
    202193    //cout << "CalcDelay: next: " << timeval_str(m_nexttrigger) << " now "
    203194    // << timeval_str(now) << endl;
     195    int64_t now = now_tv.tv_sec * 1000000LL + now_tv.tv_usec;
    204196
    205     int ret_val = (m_nexttrigger.tv_sec - now.tv_sec) * 1000000 +
    206                   (m_nexttrigger.tv_usec - now.tv_usec);
     197    int ret_val = m_nexttrigger - now;
    207198
    208199    //cout << "delay " << ret_val << endl;
    209200
    int VideoSync::CalcDelay() 
    215206            ret_val = m_frame_interval * 4;
    216207
    217208        // set nexttrigger to our new target time
    218         m_nexttrigger.tv_sec = now.tv_sec;
    219         m_nexttrigger.tv_usec = now.tv_usec;
    220         OffsetTimeval(m_nexttrigger, ret_val);
     209        m_nexttrigger = now;
     210        m_nexttrigger += ret_val;
    221211    }
    222212
    223213    if (ret_val < -m_frame_interval)
    int VideoSync::CalcDelay() 
    225215        ret_val = -m_frame_interval;
    226216
    227217        // set nexttrigger to our new target time
    228         m_nexttrigger.tv_sec = now.tv_sec;
    229         m_nexttrigger.tv_usec = now.tv_usec;
    230         OffsetTimeval(m_nexttrigger, ret_val);
     218        m_nexttrigger = now;
     219        m_nexttrigger += ret_val;
    231220    }
    232221
    233222    return ret_val;
    int VideoSync::CalcDelay() 
    244233void VideoSync::KeepPhase()
    245234{
    246235    // cerr << m_delay << endl;
    247     if (m_delay < -(m_refresh_interval/2))
    248         OffsetTimeval(m_nexttrigger, 200);
    249     else if (m_delay > -500)
    250         OffsetTimeval(m_nexttrigger, -2000);
     236    if (m_synchronous)
     237    {
     238        if (m_delay < -(m_refresh_interval - 500))
     239            m_nexttrigger += 200;
     240        else if (m_delay > -500)
     241            m_nexttrigger += -2000;
     242    }
     243    else
     244    {
     245        if (m_delay < -(m_refresh_interval + 500))
     246            m_nexttrigger += 200;
     247        else if (m_delay >= 0)
     248            m_nexttrigger += -2000;
     249    }
    251250}
    252251
    253252#ifndef _WIN32
    void DRMVideoSync::Start(void) 
    337336    VideoSync::Start();
    338337}
    339338
    340 void DRMVideoSync::WaitForFrame(int sync_delay)
     339int DRMVideoSync::WaitForFrame(int sync_delay)
    341340{
    342341    // Offset for externally-provided A/V sync delay
    343     OffsetTimeval(m_nexttrigger, sync_delay);
     342    m_nexttrigger += sync_delay;
    344343
    345344    m_delay = CalcDelay();
    346345    //cerr << "WaitForFrame at : " << m_delay;
    void DRMVideoSync::WaitForFrame(int sync_delay) 
    360359    if (m_delay > 0)
    361360    {
    362361        // Wait for any remaining retrace intervals in one pass.
    363         int n = m_delay / m_refresh_interval + 1;
     362        int n = (m_delay + m_refresh_interval - 1) / m_refresh_interval;
    364363
    365364        drm_wait_vblank_t blank;
    366365        blank.request.type = DRM_VBLANK_RELATIVE;
    void DRMVideoSync::WaitForFrame(int sync_delay) 
    370369        //cerr << "Wait " << n << " intervals. Count " << blank.request.sequence;
    371370        //cerr  << " Delay " << m_delay << endl;
    372371    }
     372    return m_delay;
    373373}
    374374
    375375void DRMVideoSync::AdvanceTrigger(void)
    void OpenGLVideoSync::Start(void) 
    497497#endif /* USING_OPENGL_VSYNC */
    498498}
    499499
    500 void OpenGLVideoSync::WaitForFrame(int sync_delay)
     500int OpenGLVideoSync::WaitForFrame(int sync_delay)
    501501{
    502502    (void) sync_delay;
    503503#ifdef USING_OPENGL_VSYNC
     504//#define GLVSYNCDEBUG
     505#ifdef GLVSYNCDEBUG
     506    int refreshcount = 0;
     507#endif
    504508    const QString msg1("First A/V Sync"), msg2("Second A/V Sync");
    505     OffsetTimeval(m_nexttrigger, sync_delay);
     509    m_nexttrigger += sync_delay;
    506510
    507511    VideoOutput *vo = dynamic_cast<VideoOutput*>(m_video_output);
    508512    if (vo && vo->IsEmbedding())
    void OpenGLVideoSync::WaitForFrame(int sync_delay) 
    510514        m_delay = CalcDelay();
    511515        if (m_delay > 0)
    512516            usleep(m_delay);
    513         return;
     517        return 0;
    514518    }
    515519
    516520    int err;
    517521    if (!m_context)
    518         return;
     522        return 0;
    519523    unsigned int frameNum = 0;
    520524
    521525    OpenGLContextLocker ctx_lock(m_context);
    522526    err = gMythGLXGetVideoSyncSGI(&frameNum);
    523527    checkGLSyncError("Frame Number Query", err);
    524528
     529#ifdef GLVSYNCDEBUG
     530    int delay1 = m_delay;
     531    int delay2;
     532#endif
    525533    // Always sync to the next retrace execpt when we are very late.
    526534    if ((m_delay = CalcDelay()) > -(m_refresh_interval/2))
    527535    {
     536#ifdef GLVSYNCDEBUG
     537        delay2 = m_delay;
     538#endif
    528539        err = gMythGLXWaitVideoSyncSGI(2, (frameNum+1)%2 ,&frameNum);
    529540        checkGLSyncError(msg1, err);
    530541        m_delay = CalcDelay();
     542#ifdef GLVSYNCDEBUG
     543        refreshcount++;
     544#endif
    531545    }
     546#ifdef GLVSYNCDEBUG
     547    else
     548        delay2 = m_delay;
     549#endif
    532550
     551#ifdef GLVSYNCDEBUG
     552    int delay3 = m_delay;
     553#endif
    533554    // Wait for any remaining retrace intervals in one pass.
    534555    if (m_delay > 0)
    535556    {
    536         uint n = m_delay / m_refresh_interval + 1;
     557        uint n = (m_delay + m_refresh_interval - 1) / m_refresh_interval;
     558#ifdef GLVSYNCDEBUG
     559        refreshcount += (int)n;
     560#endif
    537561        err = gMythGLXWaitVideoSyncSGI((n+1), (frameNum+n)%(n+1), &frameNum);
    538562        checkGLSyncError(msg2, err);
    539563        m_delay = CalcDelay();
    540564    }
     565#ifdef GLVSYNCDEBUG
     566    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString("VS: WFF: ri:%1 fi:%2 delay1:%3 delay2:%4 delay3:%5 skip:%6 finaldelay:%7")
     567            .arg(m_refresh_interval)
     568            .arg(m_frame_interval)
     569            .arg(delay1)
     570            .arg(delay2)
     571            .arg(delay3)
     572            .arg(refreshcount)
     573            .arg(m_delay)
     574           );
     575#endif
    541576
    542577#endif /* USING_OPENGL_VSYNC */
     578    return m_delay;
    543579}
    544580
    545581void OpenGLVideoSync::AdvanceTrigger(void)
    void OpenGLVideoSync::AdvanceTrigger(void) 
    548584
    549585    KeepPhase();
    550586    UpdateNexttrigger();
     587#ifdef GLVSYNCDEBUG
     588    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, "VS: AdvanceTrigger");
     589#endif
    551590#endif /* USING_OPENGL_VSYNC */
    552591}
    553592#endif /* !_WIN32 */
    bool RTCVideoSync::TryInit(void) 
    594633    return true;
    595634}
    596635
    597 void RTCVideoSync::WaitForFrame(int sync_delay)
     636int RTCVideoSync::WaitForFrame(int sync_delay)
    598637{
    599     OffsetTimeval(m_nexttrigger, sync_delay);
     638    m_nexttrigger += sync_delay;
    600639
    601640    m_delay = CalcDelay();
    602641
    void RTCVideoSync::WaitForFrame(int sync_delay) 
    609648        if ((val < 0) && (m_delay > 0))
    610649            usleep(m_delay);
    611650    }
     651    return 0;
    612652}
    613653
    614654void RTCVideoSync::AdvanceTrigger(void)
    bool VDPAUVideoSync::TryInit(void) 
    637677    return true;
    638678}
    639679
    640 void VDPAUVideoSync::WaitForFrame(int sync_delay)
     680int VDPAUVideoSync::WaitForFrame(int sync_delay)
    641681{
    642682    // Offset for externally-provided A/V sync delay
    643     OffsetTimeval(m_nexttrigger, sync_delay);
     683    m_nexttrigger += sync_delay;
    644684    m_delay = CalcDelay();
    645685
    646686    if (m_delay < 0)
    void VDPAUVideoSync::WaitForFrame(int sync_delay) 
    648688
    649689    VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output);
    650690    vo->SetNextFrameDisplayTimeOffset(m_delay);
     691    return 0;
    651692}
    652693
    653694void VDPAUVideoSync::AdvanceTrigger(void)
    bool BusyWaitVideoSync::TryInit(void) 
    674715    return true;
    675716}
    676717
    677 void BusyWaitVideoSync::WaitForFrame(int sync_delay)
     718int BusyWaitVideoSync::WaitForFrame(int sync_delay)
    678719{
    679720    // Offset for externally-provided A/V sync delay
    680     OffsetTimeval(m_nexttrigger, sync_delay);
     721    m_nexttrigger += sync_delay;
    681722
    682723    m_delay = CalcDelay();
    683724
    void BusyWaitVideoSync::WaitForFrame(int sync_delay) 
    703744        if (cnt > 1)
    704745            m_cheat -= 200;
    705746    }
     747    return 0;
    706748}
    707749
    708750void BusyWaitVideoSync::AdvanceTrigger(void)
    bool USleepVideoSync::TryInit(void) 
    725767    return true;
    726768}
    727769
    728 void USleepVideoSync::WaitForFrame(int sync_delay)
     770int USleepVideoSync::WaitForFrame(int sync_delay)
    729771{
    730772    // Offset for externally-provided A/V sync delay
    731     OffsetTimeval(m_nexttrigger, sync_delay);
     773    m_nexttrigger += sync_delay;
    732774
    733775    m_delay = CalcDelay();
    734776    if (m_delay > 0)
    735777        usleep(m_delay);
     778    return 0;
    736779}
    737780
    738781void USleepVideoSync::AdvanceTrigger(void)
  • mythtv/libs/libmythtv/vsync.h

    diff --git a/mythtv/libs/libmythtv/vsync.h b/mythtv/libs/libmythtv/vsync.h
    index f077949..f8b1c4b 100644
    a b class VideoSync 
    7070    virtual void Start(void);
    7171
    7272    /** \brief Waits for next a frame or field.
     73     *   Returns delay to real frame timing in usec
    7374     *
    7475     *   Start(void), WaitForFrame(void), and Stop(void) should
    7576     *   always be called from same thread, to prevent bad
    class VideoSync 
    7879     *  \param sync_delay time until the desired frame or field
    7980     *  \sa CalcDelay(void), KeepPhase(void)
    8081     */
    81     virtual void WaitForFrame(int sync_delay) = 0;
     82    virtual int WaitForFrame(int sync_delay) = 0;
    8283
    8384    /// \brief Use the next frame or field for CalcDelay(void)
    8485    ///        and WaitForFrame(int).
    class VideoSync 
    104105                                 uint frame_interval, uint refresh_interval,
    105106                                 bool interlaced);
    106107  protected:
    107     static void OffsetTimeval(struct timeval& tv, int offset);
    108108    void UpdateNexttrigger(void);
    109109    int CalcDelay(void);
    110110    void KeepPhase(void);
    class VideoSync 
    113113    int m_frame_interval; // of video
    114114    int m_refresh_interval; // of display
    115115    bool m_interlaced;
    116     struct timeval m_nexttrigger;
     116    int64_t m_nexttrigger;
    117117    int m_delay;
     118    bool m_synchronous;
    118119   
    119120    static int m_forceskip;
    120121};
    class DRMVideoSync : public VideoSync 
    136137    QString getName(void) const { return QString("DRM"); }
    137138    bool TryInit(void);
    138139    void Start(void);
    139     void WaitForFrame(int sync_delay);
     140    int WaitForFrame(int sync_delay);
    140141    void AdvanceTrigger(void);
    141142
    142143  private:
    class OpenGLVideoSync : public VideoSync 
    178179    QString getName(void) const { return QString("SGI OpenGL"); }
    179180    bool TryInit(void);
    180181    void Start(void);
    181     void WaitForFrame(int sync_delay);
     182    int WaitForFrame(int sync_delay);
    182183    void AdvanceTrigger(void);
    183184
    184185  private:
    class RTCVideoSync : public VideoSync 
    207208
    208209    QString getName(void) const { return QString("RTC"); }
    209210    bool TryInit(void);
    210     void WaitForFrame(int sync_delay);
     211    int WaitForFrame(int sync_delay);
    211212    void AdvanceTrigger(void);
    212213
    213214  private:
    class VDPAUVideoSync : public VideoSync 
    228229
    229230    QString getName(void) const { return QString("VDPAU"); }
    230231    bool TryInit(void);
    231     void WaitForFrame(int sync_delay);
     232    int WaitForFrame(int sync_delay);
    232233    void AdvanceTrigger(void);
    233234
    234235  private:
    class BusyWaitVideoSync : public VideoSync 
    256257
    257258    QString getName(void) const { return QString("USleep with busy wait"); }
    258259    bool TryInit(void);
    259     void WaitForFrame(int sync_delay);
     260    int WaitForFrame(int sync_delay);
    260261    void AdvanceTrigger(void);
    261262
    262263  private:
    class USleepVideoSync : public VideoSync 
    284285
    285286    QString getName(void) const { return QString("USleep"); }
    286287    bool TryInit(void);
    287     void WaitForFrame(int sync_delay);
     288    int WaitForFrame(int sync_delay);
    288289    void AdvanceTrigger(void);
    289290};
    290291#endif /* VSYNC_H_INCLUDED */