Ticket #13536: avsync_rev2_with_filter.diff

File avsync_rev2_with_filter.diff, 25.4 KB (added by pletch, 12 months ago)

This revision includes an exponential smoothing filter of the calculated audio / video sync values fed into the control loop algorithm used for adjustment. This dampens the impact of jitter present in the system reported timestamp values.

  • mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp

    diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp b/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp
    index 765371ffbe..71514ba6a4 100644
    a b void MythDVDPlayer::DisplayLastFrame(void) 
    237237    SetScanType(kScan_Progressive);
    238238    DisplayDVDButton();
    239239
    240     AVSync(nullptr, true);
     240    AVSync(nullptr);
    241241}
    242242
    243243bool MythDVDPlayer::FastForward(float Seconds)
    void MythDVDPlayer::ChangeSpeed(void) 
    457457    }
    458458}
    459459
    460 void MythDVDPlayer::AVSync(VideoFrame *Frame, bool /*LimitDelay*/)
    461 {
    462     MythPlayer::AVSync(Frame, true);
    463 }
    464 
    465460long long MythDVDPlayer::CalcMaxFFTime(long long FastFwd, bool Setjump) const
    466461{
    467462    if ((totalFrames > 0) && player_ctx->m_buffer->IsDVD() &&
    void MythDVDPlayer::StillFrameCheck(void) 
    758753            player_ctx->m_buffer->DVD()->SkipStillFrame();
    759754            m_stillFrameLength = 0;
    760755        }
    761         else {
    762             LOG(VB_GENERAL, LOG_INFO, LOC + QString("elapsed %1").arg(elapsedTime));
    763         }
    764756    }
    765757}
    766758
  • mythtv/libs/libmythtv/DVD/mythdvdplayer.h

    diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.h b/mythtv/libs/libmythtv/DVD/mythdvdplayer.h
    index 90cf3e0f87..d6d8f8c3ae 100644
    a b class MythDVDPlayer : public MythPlayer 
    4444    bool     DecoderGetFrameFFREW(void) override;
    4545    bool     DecoderGetFrameREW(void) override;
    4646    void     ChangeSpeed(void) override;
    47     void     AVSync(VideoFrame *Frame, bool LimitDelay = false) override;
    4847    void     DisplayPauseFrame(void) override;
    4948    void     PreProcessNormalFrame(void) override;
    5049    void     VideoStart(void) override;
  • mythtv/libs/libmythtv/mythplayer.cpp

    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index f7e039c0cd..c4bc9187e1 100644
    a b MythPlayer::MythPlayer(PlayerFlags flags) 
    156156      // Debugging variables
    157157      output_jmeter(new Jitterometer(LOC))
    158158{
    159     max_diverge = float(gCoreContext->GetFloatSetting
    160         ("PlayerMaxDiverge", 3.0));
    161     if (max_diverge < 1.0F)
    162         max_diverge = 1.0F;
    163 
    164159    playerThread = QThread::currentThread();
    165160#ifdef Q_OS_ANDROID
    166161    playerThreadId = gettid();
    MythPlayer::MythPlayer(PlayerFlags flags) 
    170165
    171166    vbimode = VBIMode::Parse(gCoreContext->GetSetting("VbiFormat"));
    172167    captionsEnabledbyDefault = gCoreContext->GetBoolSetting("DefaultCCMode");
    173     decode_extra_audio = gCoreContext->GetBoolSetting("DecodeExtraAudio", false);
    174168    itvEnabled         = gCoreContext->GetBoolSetting("EnableMHEG", false);
    175169    clearSavedPosition = gCoreContext->GetNumSetting("ClearSavedPosition", 1);
    176170    endExitPrompt      = gCoreContext->GetNumSetting("EndOfRecordingExitPrompt");
    MythPlayer::MythPlayer(PlayerFlags flags) 
    182176    uint tmp = mypage.toInt(&valid, 16);
    183177    ttPageNum = (valid) ? tmp : ttPageNum;
    184178    cc608.SetTTPageNum(ttPageNum);
    185     avsync2adjustms = (int64_t)gCoreContext->GetNumSetting("AVSync2AdjustMS", 10);
    186     if (avsync2adjustms < 1)
    187         avsync2adjustms = 1;
    188     if (avsync2adjustms > 40)
    189         avsync2adjustms = 40;
    190179    m_avTimer.start();
    191180}
    192181
    bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio) 
    325314    rtcbase = 0;
    326315    prior_audiotimecode = 0;
    327316    prior_videotimecode = 0;
     317    last_fix = 0.0;
    328318    SetEof(kEofStateNone);
    329319    UnpauseBuffer();
    330320    UnpauseDecoder();
    void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period) 
    15311521    if (decoder)
    15321522        m_fpsMultiplier = decoder->GetfpsMultiplier();
    15331523    frame_interval = static_cast<int>(lround(1000000.0 * frame_period) / m_fpsMultiplier);
    1534     if (!avsync_predictor_enabled)
    1535         avsync_predictor = 0;
    1536     avsync_predictor_enabled = false;
    15371524
    15381525    LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval Interval:%1 Speed:%2 Scan:%3 (Multiplier: %4)")
    15391526        .arg(frame_interval).arg(static_cast<double>(play_speed)).arg(toQString(scan)).arg(m_fpsMultiplier));
    15401527    if (play_speed < 1 || play_speed > 2 || refreshrate <= 0)
    15411528        return;
    1542 
    1543     avsync_predictor_enabled = ((frame_interval - (frame_interval / 200)) < refreshrate);
    15441529}
    15451530
    15461531void MythPlayer::ResetAVSync(void)
    15471532{
    15481533    avsync_avg = 0;
    1549     if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
    1550         avsync_predictor = 0;
    15511534    prevtc = 0;
    1552     avsync_next = avsync_interval;      // Frames till next sync check
    15531535    rtcbase = 0;
    15541536    prior_audiotimecode = 0;
    15551537    prior_videotimecode = 0;
     1538    last_fix = 0.0;
    15561539    LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
    15571540}
    15581541
    void MythPlayer::InitAVSync(void) 
    15601543{
    15611544    videosync->Start();
    15621545
    1563     avsync_adjustment = 0;
    1564 
    1565     repeat_delay = 0;
    1566 
    15671546    refreshrate = m_display->GetDisplayInfo(frame_interval).Rate();
    15681547
    1569     // Number of frames over which to average time divergence
    1570     avsync_averaging=4;
    15711548    rtcbase = 0;
    15721549    prior_audiotimecode = 0;
    15731550    prior_videotimecode = 0;
    1574 
    1575     // Allow override of averaging value
    1576     avsync_averaging = gCoreContext->GetNumSetting("AVSyncAveraging", avsync_averaging);  // Number of frames to average
    1577     if (avsync_averaging < 4)
    1578         avsync_averaging = 4;
    1579     avsync_interval = avsync_averaging / max_diverge - 1;   // Number of frames skip between sync checks
    1580     if (avsync_interval < 0)
    1581         avsync_interval = 0;
    1582     avsync_next = avsync_interval;      // Frames till next sync check
     1551    last_fix = 0.0;
    15831552
    15841553    if (!FlagIsSet(kVideoIsNull))
    15851554    {
    void MythPlayer::InitAVSync(void) 
    16001569    }
    16011570}
    16021571
    1603 int64_t MythPlayer::AVSyncGetAudiotime(void)
    1604 {
    1605     int64_t currentaudiotime = 0;
    1606     if (normal_speed)
    1607     {
    1608         currentaudiotime = audio.GetAudioTime();
    1609     }
    1610     return currentaudiotime;
    1611 }
    1612 
    1613 void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
    1614 {
    1615     if (gCoreContext->GetBoolSetting("PlaybackAVSync2", false))
    1616     {
    1617         AVSync2(buffer);
    1618         return;
    1619     }
    1620 
    1621     int repeat_pict  = 0;
    1622     int64_t timecode = audio.GetAudioTime();
    1623 
    1624     if (buffer)
    1625     {
    1626         repeat_pict   = buffer->repeat_pict;
    1627         timecode      = buffer->timecode;
    1628         disp_timecode = buffer->disp_timecode;
    1629     }
    1630 
    1631     bool decoderdeint = buffer && buffer->decoder_deinterlaced;
    1632     FrameScanType ps = m_scan;
    1633     if (kScan_Detect == m_scan || kScan_Ignore == m_scan || decoderdeint)
    1634     {
    1635         ps = kScan_Progressive;
    1636     }
    1637     else if (buffer && is_interlaced(ps))
    1638     {
    1639         ps = kScan_Interlaced;
    1640         buffer->interlaced_reversed = m_scan == kScan_Intr2ndField;
    1641     }
    1642 
    1643     // only display the second field if needed
    1644     m_double_framerate = is_interlaced(ps) && m_lastDeinterlacer2x;
    1645 
    1646     float diverge = 0.0F;
    1647     int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval;
    1648     int vsync_delay_clock = 0;
    1649     //int64_t currentaudiotime = 0;
    1650 
    1651     if (videoOutput->IsErrored())
    1652     {
    1653         LOG(VB_GENERAL, LOG_ERR, LOC +
    1654             "AVSync: Unknown error in videoOutput, aborting playback.");
    1655         SetErrored(tr("Failed to initialize A/V Sync"));
    1656         return;
    1657     }
    1658 
    1659     if (normal_speed && avsync_next==0)
    1660     {
    1661         diverge = (float)avsync_avg / (float)frame_interval;
    1662     }
    1663 
    1664     if (avsync_next > 0)
    1665     {
    1666         avsync_next--;
    1667     }
    1668     else
    1669     {
    1670         int divisor = int(abs(diverge) - max_diverge - 1.0F);
    1671         if (divisor < 1)
    1672             divisor=1;
    1673         avsync_next = avsync_interval/divisor;
    1674     }
    1675 
    1676     bool max_video_behind = diverge < -max_diverge;
    1677     bool dropframe = false;
    1678     QString dbg;
    1679 
    1680     if (avsync_predictor_enabled)
    1681     {
    1682         avsync_predictor += frame_interval + avsync_adjustment + repeat_delay;
    1683         if (avsync_predictor >= refreshrate)
    1684         {
    1685             int refreshperiodsinframe = avsync_predictor/refreshrate;
    1686             avsync_predictor -= refreshrate * refreshperiodsinframe;
    1687         }
    1688         else
    1689         {
    1690             dropframe = !FlagIsSet(kMusicChoice);
    1691             dbg = QString("A/V predict drop frame, refreshrate %1, avsync_predictor %2, diverge %3, ")
    1692             .arg(refreshrate).arg(avsync_predictor).arg(diverge);
    1693         }
    1694     }
    1695 
    1696     if (max_video_behind)
    1697     {
    1698         dropframe = !FlagIsSet(kMusicChoice);
    1699         // If video is way behind of audio, adjust for it...
    1700         dbg = QString("Video is %1 frames behind audio (too slow), ")
    1701             .arg(-diverge);
    1702     }
    1703 
    1704     if (!dropframe && avsync_audiopaused)
    1705     {
    1706         avsync_audiopaused = false;
    1707         audio.Pause(false);
    1708     }
    1709 
    1710     if (!dropframe)
    1711     {
    1712         // PGB this was orignally in the calling methods
    1713         // MythPlayer::DisplayNormalFrame and MythDVDPlayer::DisplayLastFrame
    1714         // Moved here to reduce CPU usage since the OSD was being merged
    1715         // into frames that were not being displayed, thereby causing
    1716         // interruptions and slowdowns.
    1717         osdLock.lock();
    1718         videoOutput->ProcessFrame(buffer, osd, pip_players, ps);
    1719         osdLock.unlock();
    1720     }
    1721 
    1722     if (dropframe)
    1723     {
    1724         // Reset A/V Sync
    1725         lastsync = true;
    1726         //currentaudiotime = AVSyncGetAudiotime();
    1727         LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg + "dropping frame to catch up.");
    1728         if (max_video_behind)
    1729         {
    1730             audio.Pause(true);
    1731             avsync_audiopaused = true;
    1732         }
    1733     }
    1734     else if (!FlagIsSet(kVideoIsNull))
    1735     {
    1736         // if we get here, we're actually going to do video output
    1737         osdLock.lock();
    1738         videoOutput->PrepareFrame(buffer, ps, osd);
    1739         osdLock.unlock();
    1740         // Don't wait for sync if this is a secondary PBP otherwise
    1741         // the primary PBP will become out of sync
    1742         if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP())
    1743         {
    1744             LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
    1745                 LOC + QString("AVSync waitforframe %1 %2 %3")
    1746                     .arg(frameDelay).arg(avsync_adjustment).arg(m_double_framerate));
    1747             vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment + repeat_delay);
    1748         }
    1749         else
    1750         {
    1751             vsync_delay_clock = 0;
    1752             lastsync = true;
    1753         }
    1754         //currentaudiotime = AVSyncGetAudiotime();
    1755         LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "AVSync show");
    1756         videoOutput->Show(ps);
    1757 
    1758         if (videoOutput->IsErrored())
    1759         {
    1760             LOG(VB_GENERAL, LOG_ERR, LOC + "Error condition detected "
    1761                     "in videoOutput after Show(), aborting playback.");
    1762             SetErrored(tr("Serious error detected in Video Output"));
    1763             return;
    1764         }
    1765 
    1766         if (m_double_framerate)
    1767         {
    1768             // second stage of deinterlacer processing
    1769             if (ps == kScan_Interlaced)
    1770                 ps = kScan_Intr2ndField;
    1771             osdLock.lock();
    1772             // Only double rate CPU deinterlacers require an extra call to ProcessFrame
    1773             if (GetDoubleRateOption(buffer, DEINT_CPU) && !GetDoubleRateOption(buffer, DEINT_SHADER))
    1774                 videoOutput->ProcessFrame(buffer, osd, pip_players, ps);
    1775             videoOutput->PrepareFrame(buffer, ps, osd);
    1776             osdLock.unlock();
    1777             // Display the second field
    1778             if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP())
    1779             {
    1780                 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + QString("AVSync waitforframe %1 %2 %3")
    1781                         .arg(frameDelay).arg(avsync_adjustment).arg(m_double_framerate));
    1782                 vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment);
    1783             }
    1784             videoOutput->Show(ps);
    1785         }
    1786 
    1787         repeat_delay = frame_interval * repeat_pict * 0.5;
    1788 
    1789         if (repeat_delay)
    1790             LOG(VB_TIMESTAMP, LOG_INFO, LOC +
    1791                 QString("A/V repeat_pict, adding %1 repeat delay")
    1792                     .arg(repeat_delay));
    1793     }
    1794     else
    1795     {
    1796         vsync_delay_clock = videosync->WaitForFrame(frameDelay, 0);
    1797         //currentaudiotime = AVSyncGetAudiotime();
    1798     }
    1799 
    1800     if (output_jmeter && output_jmeter->RecordCycleTime())
    1801     {
    1802         LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
    1803             QString("A/V avsync_delay: %1, avsync_avg: %2")
    1804                 .arg(avsync_delay / 1000).arg(avsync_avg / 1000));
    1805     }
    1806 
    1807     avsync_adjustment = 0;
    1808 
    1809     if (diverge > max_diverge)
    1810     {
    1811         // If audio is way behind of video, adjust for it...
    1812         // by cutting the frame rate in half for the length of this frame
    1813         avsync_adjustment = frame_interval;
    1814         lastsync = true;
    1815         LOG(VB_PLAYBACK, LOG_INFO, LOC +
    1816             QString("Video is %1 frames ahead of audio,\n"
    1817                     "\t\t\tdoubling video frame interval to slow down.")
    1818                 .arg(diverge));
    1819     }
    1820 
    1821     if (audio.HasAudioOut() && normal_speed)
    1822     {
    1823         // must be sampled here due to Show delays
    1824         int64_t currentaudiotime = audio.GetAudioTime();
    1825         LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
    1826             QString("A/V timecodes audio %1 video %2 frameinterval %3 "
    1827                     "avdel %4 avg %5 tcoffset %6 avp %7 avpen %8 avdc %9 "
    1828                     "diverge %10")
    1829                 .arg(currentaudiotime)
    1830                 .arg(timecode)
    1831                 .arg(frame_interval)
    1832                 .arg(timecode - currentaudiotime -
    1833                      (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000)
    1834                 .arg(avsync_avg)
    1835                 .arg(tc_wrap[TC_AUDIO])
    1836                 .arg(avsync_predictor)
    1837                 .arg(avsync_predictor_enabled)
    1838                 .arg(vsync_delay_clock)
    1839                 .arg(diverge)
    1840                  );
    1841         if (currentaudiotime != 0 && timecode != 0)
    1842         { // currentaudiotime == 0 after a seek
    1843             // The time at the start of this frame (ie, now) is given by
    1844             // last->timecode
    1845             if (prevtc != 0)
    1846             {
    1847                 int delta = (int)((timecode - prevtc)/play_speed) -
    1848                                   (frame_interval / 1000);
    1849                 // If timecode is off by a frame (dropped frame) wait to sync
    1850                 if (delta > frame_interval / 1200 &&
    1851                     delta < frame_interval / 1000 * 3 &&
    1852                     prevrp == 0)
    1853                 {
    1854                     // wait an extra frame interval
    1855                     LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
    1856                         QString("A/V delay %1").arg(delta));
    1857                     avsync_adjustment += frame_interval;
    1858                     // If we're duplicating a frame, it may be because
    1859                     // the container frame rate doesn't match the
    1860                     // stream frame rate.  In this case, we increment
    1861                     // the fake frame counter so that avformat
    1862                     // timestamp-based seeking will work.
    1863                     if (!decoder->HasPositionMap())
    1864                         ++framesPlayedExtra;
    1865                 }
    1866             }
    1867             prevtc = timecode;
    1868             prevrp = repeat_pict;
    1869 
    1870             // usec
    1871             avsync_delay = (timecode - currentaudiotime) * 1000 -
    1872                             (int)(vsync_delay_clock*audio.GetStretchFactor());
    1873 
    1874             // prevents major jitter when pts resets during dvd title
    1875             if (avsync_delay > 2000000 && limit_delay)
    1876                 avsync_delay = 90000;
    1877             avsync_avg = (avsync_delay + (avsync_avg * (avsync_averaging-1))) / avsync_averaging;
    1878 
    1879             int avsync_used = avsync_avg;
    1880             if (labs(avsync_used) > labs(avsync_delay))
    1881                 avsync_used = avsync_delay;
    1882 
    1883             /* If the audio time codes and video diverge, shift
    1884                the video by one interlaced field (1/2 frame) */
    1885             if (!lastsync)
    1886             {
    1887                 if (avsync_used > refreshrate)
    1888                 {
    1889                     avsync_adjustment += refreshrate;
    1890                 }
    1891                 else if (avsync_used < 0 - refreshrate)
    1892                 {
    1893                     avsync_adjustment -= refreshrate;
    1894                 }
    1895             }
    1896             else
    1897                 lastsync = false;
    1898         }
    1899         else
    1900         {
    1901             ResetAVSync();
    1902         }
    1903     }
    1904     else
    1905     {
    1906         LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
    1907             QString("A/V no sync proc ns:%1").arg(normal_speed));
    1908     }
    1909 }
    1910 
    19111572void MythPlayer::WaitForTime(int64_t framedue)
    19121573{
    19131574    int64_t unow = m_avTimer.nsecsElapsed() / 1000;
    void MythPlayer::WaitForTime(int64_t framedue) 
    19171578}
    19181579
    19191580#define AVSYNC_MAX_LATE 10000000
    1920 void MythPlayer::AVSync2(VideoFrame *buffer)
     1581void MythPlayer::AVSync(VideoFrame *buffer)
    19211582{
    19221583    if (videoOutput->IsErrored())
    19231584    {
    void MythPlayer::AVSync2(VideoFrame *buffer) 
    19361597    int64_t lateness = 0;
    19371598    auto playspeed1000 = static_cast<int64_t>(1000.0F / play_speed);
    19381599    bool reset = false;
     1600    // controller gain
     1601    static float const s_av_control_gain = 0.04F;
     1602    // time weighted exponential filter coefficient
     1603    static float const s_sync_fc = 0.6F;
    19391604
    19401605    while (framedue == 0)
    19411606    {
    void MythPlayer::AVSync2(VideoFrame *buffer) 
    20101675                audio_adjustment = 0;
    20111676            }
    20121677            int sign = audio_adjustment < 0 ? -1 : 1;
    2013             int64_t fix_amount = audio_adjustment * sign;
    2014             if (fix_amount > avsync2adjustms)
    2015                 fix_amount = avsync2adjustms;
    2016             // Faster catch-up when off by more than 200 ms
    2017             if (audio_adjustment * sign > 200)
    2018                 // fix the sync within 15 - 20 frames
    2019                 fix_amount = audio_adjustment * sign / 15;
     1678            float fix_amount = (last_fix * s_sync_fc + (1 - s_sync_fc) * audio_adjustment) * sign * s_av_control_gain;
     1679            last_fix = fix_amount * sign;
    20201680            auto speedup1000 = static_cast<int64_t>(1000 * play_speed);
    20211681            rtcbase -= static_cast<int64_t>(1000000 * fix_amount * sign / speedup1000);
    2022             if (audio_adjustment * sign > 20 || (framesPlayed % 400 == 0))
     1682            if (audio_adjustment * sign > 20)
    20231683                LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sync: Audio %1 by %2 ms")
    20241684                    .arg(audio_adjustment > 0 ? "ahead" : "behind").arg(abs(audio_adjustment)));
    20251685            if (audio_adjustment > 200)
    void MythPlayer::AVSync2(VideoFrame *buffer) 
    21351795
    21361796    LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
    21371797        QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 "
    2138                 "audioadj=%4 tcoffset=%5 unow=%6 udue=%7")
     1798                "audioadj=%4 tcoffset=%5 unow=%6 udue=%7 ")
    21391799            .arg(prior_audiotimecode)
    21401800            .arg(prior_videotimecode)
    21411801            .arg(frame_interval)
    void MythPlayer::DisplayNormalFrame(bool check_prebuffer) 
    23712031    AutoDeint(frame);
    23722032    detect_letter_box->SwitchTo(frame);
    23732033
    2374     AVSync(frame, false);
     2034    AVSync(frame);
    23752035
    23762036    // If PiP then keep this frame for MythPlayer::GetCurrentFrame
    23772037    if (!player_ctx->IsPIP())
    void MythPlayer::VideoStart(void) 
    25002160    SetPlaying(true);
    25012161    ClearAfterSeek(false);
    25022162
    2503     avsync_delay = 0;
    2504     avsync_avg = 0;
    2505     avsync_next = avsync_interval;      // Frames till next sync check
     2163    avsync_avg = 0;  // Frames till next sync check
    25062164    refreshrate = 0;
    2507     lastsync = false;
    25082165
    25092166    EnableFrameRateMonitor();
    25102167    refreshrate = frame_interval;
    void MythPlayer::GetPlaybackData(InfoMap &infoMap) 
    50464703    infoMap.insert("storagerate", player_ctx->m_buffer->GetStorageRate());
    50474704    infoMap.insert("bufferavail", player_ctx->m_buffer->GetAvailableBuffer());
    50484705    infoMap.insert("buffersize",  QString::number(player_ctx->m_buffer->GetBufferSize() >> 20));
    5049     if (gCoreContext->GetBoolSetting("PlaybackAVSync2", false))
    5050     {
    5051         int avsync = avsync_avg / 1000;
    5052         infoMap.insert("avsync", tr("%1 ms").arg(avsync));
    5053     }
    5054     else
    5055         infoMap.insert("avsync", QString::number((float)avsync_avg / (float)frame_interval, 'f', 2));
     4706    int avsync = avsync_avg / 1000;
     4707    infoMap.insert("avsync", tr("%1 ms").arg(avsync));
     4708
    50564709    if (videoOutput)
    50574710    {
    50584711        QString frames = QString("%1/%2").arg(videoOutput->ValidVideoFrames())
  • mythtv/libs/libmythtv/mythplayer.h

    diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
    index 76260cf118..37d3231b44 100644
    a b class MTV_PUBLIC MythPlayer 
    620620    // Private A/V Sync Stuff
    621621    void  WrapTimecode(int64_t &timecode, TCTypes tc_type);
    622622    void  InitAVSync(void);
    623     virtual void AVSync(VideoFrame *buffer, bool limit_delay = false);
    624     // New video sync method
    625     void AVSync2(VideoFrame *buffer);
     623    virtual void AVSync(VideoFrame *buffer);
    626624    void  ResetAVSync(void);
    627     int64_t AVSyncGetAudiotime(void);
    628625    void  SetFrameInterval(FrameScanType scan, double frame_period);
    629     void WaitForTime(int64_t framedue);
     626    void  WaitForTime(int64_t framedue);
    630627
    631628    // Private LiveTV stuff
    632629    void  SwitchToProgram(void);
    class MTV_PUBLIC MythPlayer 
    825822
    826823    // Audio and video synchronization stuff
    827824    VideoSync *videosync                {nullptr};
    828     int        avsync_delay             {0};
    829     int        avsync_adjustment        {0};
    830825    int        avsync_avg               {0};
    831826    int        avsync_predictor         {0};
    832     bool       avsync_predictor_enabled {false};
    833827    int        refreshrate              {0};
    834     bool       lastsync                 {false};
    835     bool       decode_extra_audio       {false};
    836     int        repeat_delay             {0};
    837828    int64_t    disp_timecode            {0};
    838829    bool       avsync_audiopaused       {false};
    839     float      max_diverge              {3.0F};  // from setting PlayerMaxDiverge default 2
    840     // AVSync for Raspberry Pi digital streams
    841     int        avsync_averaging         {4}; // Number of frames to average
    842     int        avsync_interval          {0}; // Number of frames skip between sync checks
    843     int        avsync_next              {0}; // Frames till next sync check
     830    int64_t    rtcbase                   {0}; // real time clock base for presentation time (microsecs)
     831    int64_t    maxtcval                  {0}; // maximum to date video tc
     832    int        maxtcframes               {0}; // number of frames seen since max to date tc
     833    int        numdroppedframes          {0}; // number of consecutive dropped frames.
     834    int64_t    prior_audiotimecode       {0}; // time code from prior frame
     835    int64_t    prior_videotimecode       {0}; // time code from prior frame
     836    float      last_fix                  {0.0F}; //last sync adjustment to prior frame
     837    int64_t    m_timeOffsetBase          {0};
    844838
    845839    // Time Code stuff
    846840    int        prevtc                   {0}; ///< 32 bit timecode if last VideoFrame shown
    class MTV_PUBLIC MythPlayer 
    849843    int64_t    tc_lastval[TCTYPESMAX]   {};
    850844    int64_t    savedAudioTimecodeOffset {0};
    851845
    852     // AVSync2
    853     int64_t   rtcbase                   {0}; // real time clock base for presentation time (microsecs)
    854     int64_t   maxtcval                  {0}; // maximum to date video tc
    855     int       maxtcframes               {0}; // number of frames seen since max to date tc
    856     int64_t   avsync2adjustms           {10};// number of milliseconds to adjust for av sync errors
    857     int       numdroppedframes          {0}; // number of consecutive dropped frames.
    858     int64_t   prior_audiotimecode       {0}; // time code from prior frame
    859     int64_t   prior_videotimecode       {0}; // time code from prior frame
    860     int64_t   m_timeOffsetBase          {0};
    861 
    862846    // LiveTV
    863847    TV *m_tv                            {nullptr};
    864848    bool isDummy                        {false};
  • mythtv/programs/mythfrontend/globalsettings.cpp

    diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
    index acc800d14e..4c79123891 100644
    a b static HostTextEditSetting *VAAPIDevice() 
    111111}
    112112#endif
    113113
    114 static HostCheckBoxSetting *PlaybackAVSync2()
    115 {
    116     auto *gc = new HostCheckBoxSetting("PlaybackAVSync2");
    117 
    118     gc->setLabel(PlaybackSettings::tr("Enable new timestamp based playback speed (AVSync2)"));
    119 
    120     gc->setHelpText(PlaybackSettings::tr("Simplified timing and synchronization method. "
    121         "This may offer smoother video playback. Note there is a setting that can be used "
    122         "for fine tuning playback (press right arrow)."));
    123     gc->setValue(false);
    124 
    125     return gc;
    126 }
    127 
    128 static HostSpinBoxSetting *AVSync2AdjustMS()
    129 // was previously *DecodeExtraAudio()
    130 {
    131     auto *gc = new HostSpinBoxSetting("AVSync2AdjustMS",1,40,1,1);
    132 
    133     gc->setLabel(PlaybackSettings::tr("AVSync2 audio correction (ms)"));
    134 
    135     gc->setValue(10);
    136 
    137     gc->setHelpText(PlaybackSettings::tr(
    138         "When using AVSync2, if video playback is speeding up and slowing down every few seconds, reduce "
    139         "this value. For quicker recovery of audio sync after jumps, increase this value. "
    140         "Values can be from 1 to 40. Default is 10."));
    141     return gc;
    142 }
    143 
    144114#if CONFIG_DEBUGTYPE
    145115static HostCheckBoxSetting *FFmpegDemuxer()
    146116{
    void PlaybackSettings::Load(void) 
    42774247#ifdef USING_VAAPI
    42784248    advanced->addChild(VAAPIDevice());
    42794249#endif
    4280     HostCheckBoxSetting *avsync2 = PlaybackAVSync2();
    4281     advanced->addChild(avsync2);
    4282     avsync2->addTargetedChild("1",AVSync2AdjustMS());
    42834250
    42844251    addChild(advanced);
    42854252