Ticket #13176: 0001-mythplayer-Fix-issues-with-vsync.patch

File 0001-mythplayer-Fix-issues-with-vsync.patch, 17.9 KB (added by Brad Martin <mythtv@…>, 6 years ago)
  • mythtv/libs/libmythtv/mythplayer.cpp

    From 52297817b2b13e1bac750ed1f0373d951994faea Mon Sep 17 00:00:00 2001
    From: Brad Martin <mythtv@fatlxception.org>
    Date: Mon, 13 Nov 2017 21:39:14 -0500
    Subject: [PATCH] mythplayer: Fix issues with vsync
    
    Vsync was broken with various combinations of:
     * 2x deinterlacing
     * High audio stretch factors (1.8x+)
     * Video streams using repeat_pict
    
    This was due to a combination of:
     * avsync_predictor failing to predict the correct frame interval
     * The vsync implementation trying to clamp the frame delay to a small
       multiple of the wrong frame interval, due to getting out sync with
       the interval and interlace setting at any given moment.
    
    With this change, the vsync method no longer tries to independently
    track the frame interval and interlace setting; instead, this is
    passed on a frame-by-frame basis.
    
    Additionally, the avsync_predictor is corrected to take into account
    additional delays beyond the nominal frame interval.
    ---
     mythtv/libs/libmythtv/mythplayer.cpp | 22 ++++-----
     mythtv/libs/libmythtv/vsync.cpp      | 88 ++++++++++++++++--------------------
     mythtv/libs/libmythtv/vsync.h        | 47 ++++++++-----------
     3 files changed, 65 insertions(+), 92 deletions(-)
    
    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index 3db086f..423f855 100644
    a b void MythPlayer::SetVideoParams(int width, int height, double fps, 
    843843        if (ffrew_skip != 0 && ffrew_skip != 1)
    844844        {
    845845            UpdateFFRewSkip();
    846             videosync->setFrameInterval(frame_interval);
    847846        }
    848847        else
    849848        {
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 
    19021901
    19031902    if (avsync_predictor_enabled)
    19041903    {
    1905         avsync_predictor += frame_interval;
     1904        avsync_predictor += frame_interval + avsync_adjustment + repeat_delay;
    19061905        if (avsync_predictor >= refreshrate)
    19071906        {
    19081907            int refreshperiodsinframe = avsync_predictor/refreshrate;
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 
    19681967            LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
    19691968                LOC + QString("AVSync waitforframe %1 %2")
    19701969                    .arg(avsync_adjustment).arg(m_double_framerate));
    1971             vsync_delay_clock = videosync->WaitForFrame
    1972                                 (frameDelay + avsync_adjustment + repeat_delay);
     1970            vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment + repeat_delay);
    19731971        }
    19741972        else
    19751973        {
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 
    20062004            osdLock.unlock();
    20072005            // Display the second field
    20082006            if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP())
    2009                 vsync_delay_clock = videosync->WaitForFrame(frameDelay +
    2010                                                         avsync_adjustment);
     2007                vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment);
    20112008            videoOutput->Show(ps);
    20122009        }
    20132010
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) 
    20202017    }
    20212018    else
    20222019    {
    2023         vsync_delay_clock = videosync->WaitForFrame(frameDelay);
     2020        vsync_delay_clock = videosync->WaitForFrame(frameDelay, 0);
    20242021        //currentaudiotime = AVSyncGetAudiotime();
    20252022    }
    20262023
    void MythPlayer::VideoStart(void) 
    24662463
    24672464    if (player_ctx->IsPIP() && FlagIsSet(kVideoIsNull))
    24682465    {
    2469         videosync = new DummyVideoSync(videoOutput, fr_int, 0, false);
     2466        videosync = new DummyVideoSync(videoOutput, 0);
    24702467    }
    24712468    else if (FlagIsSet(kVideoIsNull))
    24722469    {
    2473         videosync = new USleepVideoSync(videoOutput, fr_int, 0, false);
     2470        videosync = new USleepVideoSync(videoOutput, 0);
    24742471    }
    24752472    else if (videoOutput)
    24762473    {
    void MythPlayer::VideoStart(void) 
    24812478
    24822479        m_double_process = videoOutput->IsExtraProcessingRequired();
    24832480
    2484         videosync = VideoSync::BestMethod(
    2485             videoOutput, (uint)fr_int, (uint)rf_int, m_double_framerate);
     2481        videosync = VideoSync::BestMethod(videoOutput, (uint)rf_int);
    24862482
    24872483        // Make sure video sync can do it
    24882484        if (videosync != NULL && m_double_framerate)
    void MythPlayer::VideoStart(void) 
    24982494    }
    24992495    if (!videosync)
    25002496    {
    2501         videosync = new BusyWaitVideoSync(
    2502             videoOutput, fr_int, rf_int, m_double_framerate);
     2497        videosync = new BusyWaitVideoSync(videoOutput, rf_int);
    25032498    }
    25042499
    25052500    InitAVSync();
    void MythPlayer::ChangeSpeed(void) 
    37673762    normal_speed = next_normal_speed;
    37683763
    37693764    bool skip_changed = UpdateFFRewSkip();
    3770     videosync->setFrameInterval(frame_interval);
    37713765
    37723766    if (skip_changed && videoOutput)
    37733767    {
  • mythtv/libs/libmythtv/vsync.cpp

    diff --git a/mythtv/libs/libmythtv/vsync.cpp b/mythtv/libs/libmythtv/vsync.cpp
    index 1cb1164..5d0111f 100644
    a b int VideoSync::m_forceskip = 0; 
    5757#define TESTVIDEOSYNC(NAME) \
    5858    do { if (++m_forceskip > skip) \
    5959    { \
    60         trial = new NAME (video_output,     frame_interval, \
    61                           refresh_interval, halve_frame_interval); \
     60        trial = new NAME (video_output, refresh_interval); \
    6261        if (trial->TryInit()) \
    6362        { \
    6463            m_forceskip = skip; \
    int VideoSync::m_forceskip = 0; 
    7069
    7170#define LOC QString("VSYNC: ")
    7271
    73 /** \fn VideoSync::BestMethod(VideoOutput*,uint,uint,bool)
     72/** \fn VideoSync::BestMethod(VideoOutput*,uint)
    7473 *  \brief Returns the most sophisticated video sync method available.
    7574 */
    7675VideoSync *VideoSync::BestMethod(VideoOutput *video_output,
    77                                  uint frame_interval, uint refresh_interval,
    78                                  bool halve_frame_interval)
     76                                 uint refresh_interval)
    7977{
    8078    VideoSync *trial = NULL;
    8179    tryingVideoSync  = true;
    VideoSync *VideoSync::BestMethod(VideoOutput *video_output, 
    108106    return NULL;
    109107}
    110108
    111 /** \fn VideoSync::VideoSync(VideoOutput*,int,int,bool)
    112  *  \brief Used by BestMethod(VideoOutput*,uint,uint,bool) to initialize
     109/** \fn VideoSync::VideoSync(VideoOutput*,int)
     110 *  \brief Used by BestMethod(VideoOutput*,uint) to initialize
    113111 *         video synchronization method.
    114112 */
    115 VideoSync::VideoSync(VideoOutput *video_output,
    116                      int frameint, int refreshint,
    117                      bool halve_frame_interval) :
    118     m_video_output(video_output),   m_frame_interval(frameint),
    119     m_refresh_interval(refreshint), m_interlaced(halve_frame_interval),
     113VideoSync::VideoSync(VideoOutput *video_output, int refreshint) :
     114    m_video_output(video_output), m_refresh_interval(refreshint),
    120115    m_nexttrigger(0), m_delay(-1)
    121116{
    122117}
    void VideoSync::Start(void) 
    133128    m_nexttrigger = GetTime();
    134129}
    135130
    136 /** \fn VideoSync::CalcDelay()
     131/** \fn VideoSync::CalcDelay(int)
    137132 *  \brief Calculates the delay to the next frame.
    138133 *
    139134 *   Regardless of the timing method, if delay is greater than four full
    void VideoSync::Start(void) 
    144139 *   Also prevent the nexttrigger from falling too far in the past in case
    145140 *   we are trying to speed up video output faster than possible.
    146141 */
    147 int VideoSync::CalcDelay()
     142int VideoSync::CalcDelay(int nominal_frame_interval)
    148143{
    149144    int64_t now = GetTime();
    150145#if 0
    int VideoSync::CalcDelay() 
    158153    LOG(VB_GENERAL, LOG_DEBUG, QString("delay %1").arg(ret_val));
    159154#endif
    160155
    161     if (ret_val > m_frame_interval * 4)
     156    if (ret_val > nominal_frame_interval * 4)
    162157    {
    163         if (m_interlaced)
    164             ret_val = (m_frame_interval / 2) * 4;
    165         else
    166             ret_val = m_frame_interval * 4;
     158        ret_val = nominal_frame_interval * 4;
    167159
    168160        // set nexttrigger to our new target time
    169161        m_nexttrigger = now + ret_val;
    170162    }
    171163
    172     if (ret_val < -m_frame_interval && m_frame_interval >= m_refresh_interval)
     164    if (ret_val < -nominal_frame_interval && nominal_frame_interval >= m_refresh_interval)
    173165    {
    174         ret_val = -m_frame_interval;
     166        ret_val = -nominal_frame_interval;
    175167
    176168        // set nexttrigger to our new target time
    177169        m_nexttrigger = now + ret_val;
    static int drmWaitVBlank(int fd, drm_wait_vblank_t *vbl) 
    240232
    241233const char *DRMVideoSync::sm_dri_dev = "/dev/dri/card0";
    242234
    243 DRMVideoSync::DRMVideoSync(VideoOutput *vo, int fr, int ri, bool intl) :
    244     VideoSync(vo, fr, ri, intl)
     235DRMVideoSync::DRMVideoSync(VideoOutput *vo, int ri) :
     236    VideoSync(vo, ri)
    245237{
    246238    m_dri_fd = -1;
    247239}
    void DRMVideoSync::Start(void) 
    289281    VideoSync::Start();
    290282}
    291283
    292 int DRMVideoSync::WaitForFrame(int sync_delay)
     284int DRMVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay)
    293285{
    294286    // Offset for externally-provided A/V sync delay
    295     m_nexttrigger += sync_delay;
     287    m_nexttrigger += nominal_frame_interval + extra_delay;
    296288
    297     m_delay = CalcDelay();
     289    m_delay = CalcDelay(nominal_frame_interval);
    298290#if 0
    299291    LOG(VB_GENERAL, LOG_DEBUG, QString("WaitForFrame at : %1").arg(m_delay));
    300292#endif
    int DRMVideoSync::WaitForFrame(int sync_delay) 
    306298        blank.request.type = DRM_VBLANK_RELATIVE;
    307299        blank.request.sequence = 1;
    308300        drmWaitVBlank(m_dri_fd, &blank);
    309         m_delay = CalcDelay();
     301        m_delay = CalcDelay(nominal_frame_interval);
    310302#if 0
    311303        LOG(VB_GENERAL, LOG_DEBUG, QString("Delay at sync: %1").arg(m_delay));
    312304#endif
    int DRMVideoSync::WaitForFrame(int sync_delay) 
    321313        blank.request.type = DRM_VBLANK_RELATIVE;
    322314        blank.request.sequence = n;
    323315        drmWaitVBlank(m_dri_fd, &blank);
    324         m_delay = CalcDelay();
     316        m_delay = CalcDelay(nominal_frame_interval);
    325317#if 0
    326318        LOG(VB_GENERAL, LOG_DEBUG,
    327319            QString("Wait %1 intervals. Count %2 Delay %3")
    int DRMVideoSync::WaitForFrame(int sync_delay) 
    335327
    336328#ifdef __linux__
    337329#define RTCRATE 1024
    338 RTCVideoSync::RTCVideoSync(VideoOutput *vo, int fi, int ri, bool intr) :
    339     VideoSync(vo, fi, ri, intr)
     330RTCVideoSync::RTCVideoSync(VideoOutput *vo, int ri) :
     331    VideoSync(vo, ri)
    340332{
    341333    m_rtcfd = -1;
    342334}
    bool RTCVideoSync::TryInit(void) 
    375367    return true;
    376368}
    377369
    378 int RTCVideoSync::WaitForFrame(int sync_delay)
     370int RTCVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay)
    379371{
    380     m_nexttrigger += sync_delay;
     372    m_nexttrigger += nominal_frame_interval + extra_delay;
    381373
    382     m_delay = CalcDelay();
     374    m_delay = CalcDelay(nominal_frame_interval);
    383375
    384376    unsigned long rtcdata;
    385377    while (m_delay > 0)
    386378    {
    387379        ssize_t val = read(m_rtcfd, &rtcdata, sizeof(rtcdata));
    388         m_delay = CalcDelay();
     380        m_delay = CalcDelay(nominal_frame_interval);
    389381
    390382        if ((val < 0) && (m_delay > 0))
    391383            usleep(m_delay);
    int RTCVideoSync::WaitForFrame(int sync_delay) 
    394386}
    395387#endif /* __linux__ */
    396388
    397 BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo,
    398                                      int fr, int ri, bool intl) :
    399     VideoSync(vo, fr, ri, intl)
     389BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo, int ri) :
     390    VideoSync(vo, ri)
    400391{
    401392    m_cheat = 5000;
    402393    m_fudge = 0;
    bool BusyWaitVideoSync::TryInit(void) 
    411402    return true;
    412403}
    413404
    414 int BusyWaitVideoSync::WaitForFrame(int sync_delay)
     405int BusyWaitVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay)
    415406{
    416407    // Offset for externally-provided A/V sync delay
    417     m_nexttrigger += sync_delay;
     408    m_nexttrigger += nominal_frame_interval + extra_delay;
    418409
    419     m_delay = CalcDelay();
     410    m_delay = CalcDelay(nominal_frame_interval);
    420411
    421412    if (m_delay > 0)
    422413    {
    int BusyWaitVideoSync::WaitForFrame(int sync_delay) 
    429420
    430421        // If late, draw the frame ASAP.  If early, hold the CPU until
    431422        // half as late as the previous frame (fudge).
    432         m_delay = CalcDelay();
    433         m_fudge = min(m_fudge, m_frame_interval);
     423        m_delay = CalcDelay(nominal_frame_interval);
     424        m_fudge = min(m_fudge, nominal_frame_interval);
    434425        while (m_delay + m_fudge > 0)
    435426        {
    436             m_delay = CalcDelay();
     427            m_delay = CalcDelay(nominal_frame_interval);
    437428            cnt++;
    438429        }
    439430        m_fudge = abs(m_delay / 2);
    int BusyWaitVideoSync::WaitForFrame(int sync_delay) 
    443434    return 0;
    444435}
    445436
    446 USleepVideoSync::USleepVideoSync(VideoOutput *vo,
    447                                  int fr, int ri, bool intl) :
    448     VideoSync(vo, fr, ri, intl)
     437USleepVideoSync::USleepVideoSync(VideoOutput *vo, int ri) :
     438    VideoSync(vo, ri)
    449439{
    450440}
    451441
    bool USleepVideoSync::TryInit(void) 
    458448    return true;
    459449}
    460450
    461 int USleepVideoSync::WaitForFrame(int sync_delay)
     451int USleepVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay)
    462452{
    463453    // Offset for externally-provided A/V sync delay
    464     m_nexttrigger += sync_delay;
     454    m_nexttrigger += nominal_frame_interval + extra_delay;
    465455
    466     m_delay = CalcDelay();
     456    m_delay = CalcDelay(nominal_frame_interval);
    467457    if (m_delay > 0)
    468458        usleep(m_delay);
    469459    return 0;
  • mythtv/libs/libmythtv/vsync.h

    diff --git a/mythtv/libs/libmythtv/vsync.h b/mythtv/libs/libmythtv/vsync.h
    index 94cbd4e..2e0b79b 100644
    a b class VideoSync 
    4646// virtual base class
    4747{
    4848  public:
    49     VideoSync(VideoOutput*, int fi, int ri, bool intr);
     49    VideoSync(VideoOutput*, int ri);
    5050    virtual ~VideoSync() {}
    5151
    5252    /// \brief Returns name of instanciated VSync method.
    class VideoSync 
    6969     *   always be called from same thread, to prevent bad
    7070     *   interactions with threads.
    7171     *
    72      *  \param sync_delay time until the desired frame or field
    73      *  \sa CalcDelay(void), KeepPhase(void)
     72     *  \param nominal_frame_interval the frame interval normally expected
     73     *  \param extra_delay extra time beyond nominal until the desired frame or field
     74     *  \sa CalcDelay(int), KeepPhase(void)
    7475     */
    75     virtual int WaitForFrame(int sync_delay) = 0;
     76    virtual int WaitForFrame(int nominal_frame_interval, int extra_delay) = 0;
    7677
    7778    /// \brief Returns the (minimum) refresh interval of the output device.
    7879    int getRefreshInterval(void) const { return m_refresh_interval; }
    7980    /// \brief Sets the refresh interval of the output device.
    8081    void setRefreshInterval(int ri) { m_refresh_interval = ri; }
    8182
    82     virtual void setFrameInterval(int fi) { m_frame_interval = fi; };
    83 
    8483    /** \brief Stops VSync; must be called from main thread.
    8584     *
    8685     *   Start(void), WaitForFrame(void), and Stop(void) should
    class VideoSync 
    9089    virtual void Stop(void) {}
    9190
    9291    // documented in vsync.cpp
    93     static VideoSync *BestMethod(VideoOutput*,
    94                                  uint frame_interval, uint refresh_interval,
    95                                  bool interlaced);
     92    static VideoSync *BestMethod(VideoOutput *, uint refresh_interval);
     93
    9694  protected:
    9795    int64_t GetTime(void);
    98     int CalcDelay(void);
     96    int CalcDelay(int nominal_frame_interval);
    9997    void KeepPhase(void) MDEPRECATED;
    10098
    10199    VideoOutput *m_video_output;
    102     int m_frame_interval; // of video
    103100    int m_refresh_interval; // of display
    104     bool m_interlaced;
    105101    int64_t m_nexttrigger;
    106102    int m_delay;
    107103   
    class VideoSync 
    118114class DRMVideoSync : public VideoSync
    119115{
    120116  public:
    121     DRMVideoSync(VideoOutput*,
    122                  int frame_interval, int refresh_interval, bool interlaced);
     117    DRMVideoSync(VideoOutput *, int refresh_interval);
    123118    ~DRMVideoSync();
    124119
    125120    QString getName(void) const { return QString("DRM"); }
    126121    bool TryInit(void);
    127122    void Start(void);
    128     int WaitForFrame(int sync_delay);
     123    int WaitForFrame(int nominal_frame_interval, int extra_delay) override;
    129124
    130125  private:
    131126    int m_dri_fd;
    class DRMVideoSync : public VideoSync 
    148143class RTCVideoSync : public VideoSync
    149144{
    150145  public:
    151     RTCVideoSync(VideoOutput*,
    152                  int frame_interval, int refresh_interval, bool interlaced);
     146    RTCVideoSync(VideoOutput *, int refresh_interval);
    153147    ~RTCVideoSync();
    154148
    155149    QString getName(void) const { return QString("RTC"); }
    156150    bool TryInit(void);
    157     int WaitForFrame(int sync_delay);
     151    int WaitForFrame(int nominal_frame_interval, int extra_delay) override;
    158152
    159153  private:
    160154    int m_rtcfd;
    class RTCVideoSync : public VideoSync 
    174168class BusyWaitVideoSync : public VideoSync
    175169{
    176170  public:
    177     BusyWaitVideoSync(VideoOutput*,
    178                       int frame_interval, int refresh_interval,
    179                       bool interlaced);
     171    BusyWaitVideoSync(VideoOutput *, int refresh_interval);
    180172    ~BusyWaitVideoSync();
    181173
    182174    QString getName(void) const { return QString("USleep with busy wait"); }
    183175    bool TryInit(void);
    184     int WaitForFrame(int sync_delay);
     176    int WaitForFrame(int nominal_frame_interval, int extra_delay) override;
    185177
    186178  private:
    187179    int m_cheat;
    class BusyWaitVideoSync : public VideoSync 
    201193class USleepVideoSync : public VideoSync
    202194{
    203195  public:
    204     USleepVideoSync(VideoOutput*,
    205                     int frame_interval, int refresh_interval,
    206                     bool interlaced);
     196    USleepVideoSync(VideoOutput *, int refresh_interval);
    207197    ~USleepVideoSync();
    208198
    209199    QString getName(void) const { return QString("USleep"); }
    210200    bool TryInit(void);
    211     int WaitForFrame(int sync_delay);
     201    int WaitForFrame(int nominal_frame_interval, int extra_delay) override;
    212202};
    213203
    214204class DummyVideoSync : public VideoSync
    215205{
    216206  public:
    217     DummyVideoSync(VideoOutput* vo, int fr, int ri, bool intl)
    218      : VideoSync(vo, fr, ri, intl) { }
     207    DummyVideoSync(VideoOutput* vo, int ri) : VideoSync(vo, ri) { }
    219208    ~DummyVideoSync() { }
    220209
    221210    QString getName(void) const { return QString("Dummy"); }
    222211    bool TryInit(void) { return true; }
    223     int WaitForFrame(int sync_delay) { return 0; }
     212    int WaitForFrame(int nominal_frame_interval, int extra_delay) override { return 0; }
    224213};
    225214#endif /* VSYNC_H_INCLUDED */