Ticket #7964: mythtv_smoothsync.13.patch

File mythtv_smoothsync.13.patch, 12.9 KB (added by Mark Spieth, 15 years ago)

update after r26895

  • mythtv/libs/libmythtv/mythplayer.cpp

    smoother vsync with predictive frame skipping
    
    From: Mark Spieth <mspieth@digivation.com.au>
    
    
    ---
     mythtv/libs/libmythtv/mythplayer.cpp |  160 ++++++++++++++++++++++++++++------
     mythtv/libs/libmythtv/mythplayer.h   |    5 +
     2 files changed, 135 insertions(+), 30 deletions(-)
    
    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index 5368905..8d60f4c 100644
    a b MythPlayer::MythPlayer(bool muted)  
    236236      // Audio and video synchronization stuff
    237237      videosync(NULL),              avsync_delay(0),
    238238      avsync_adjustment(0),         avsync_avg(0),
     239      avsync_predictor(0),          avsync_predictor_enabled(false),
    239240      refreshrate(0),
    240241      lastsync(false),              repeat_delay(0),
    241242      // Time Code stuff
    void MythPlayer::SetVideoParams(int width, int height, double fps,  
    869870        video_frame_rate = fps;
    870871        float temp_speed = (play_speed == 0.0f) ?
    871872            audio.GetStretchFactor() : play_speed;
    872         frame_interval = (int)(1000000.0f / video_frame_rate / temp_speed);
     873        SetFrameInterval(kScan_Progressive, 1.0 / (video_frame_rate * temp_speed));
    873874    }
    874875
    875876    if (videoOutput)
    int MythPlayer::NextCaptionTrack(int mode)  
    16081609    return NextCaptionTrack(nextmode);
    16091610}
    16101611
     1612void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
     1613{
     1614    frame_interval = (int)(1000000.0f * frame_period + 0.5f);
     1615    if (!avsync_predictor_enabled)
     1616        avsync_predictor = 0;
     1617    avsync_predictor_enabled = false;
     1618
     1619    VERBOSE(VB_PLAYBACK, LOC + QString("SetFrameInterval ps:%1 scan:%2")
     1620            .arg(play_speed).arg(scan)
     1621           );
     1622    if (play_speed < 1 || play_speed > 2 || refreshrate <= 0)
     1623        return;
     1624
     1625    avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) < refreshrate);
     1626}
     1627
     1628void MythPlayer::ResetAVSync(void)
     1629{
     1630    avsync_avg = 0;
     1631    if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
     1632        avsync_predictor = 0;
     1633    prevtc = 0;
     1634    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V sync reset");
     1635}
     1636
    16111637void MythPlayer::InitAVSync(void)
    16121638{
    16131639    videosync->Start();
    void MythPlayer::InitAVSync(void)  
    16311657                       .arg(1000000.0 / frame_interval, 0, 'f', 3);
    16321658        VERBOSE(VB_PLAYBACK, LOC + msg);
    16331659
     1660        SetFrameInterval(m_scan, 1.0 / (video_frame_rate * play_speed));
     1661
    16341662        // try to get preferential scheduling, but ignore if we fail to.
    16351663        myth_nice(-19);
    16361664    }
    16371665}
    16381666
     1667int64_t MythPlayer::AVSyncGetAudiotime(void)
     1668{
     1669    int64_t currentaudiotime = 0;
     1670    if (normal_speed)
     1671    {
     1672        currentaudiotime = audio.GetAudioTime();
     1673    }
     1674    return currentaudiotime;
     1675}
     1676
    16391677#define MAXDIVERGE  3.0f
    16401678#define DIVERGELIMIT 30.0f
    16411679void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
    16421680{
    16431681    int repeat_pict  = 0;
    1644     int64_t timecode = audio.GetAudioTime();
     1682    int64_t timecode = 0;
    16451683
    16461684    if (buffer)
    16471685    {
    16481686        repeat_pict = buffer->repeat_pict;
    16491687        timecode    = buffer->timecode;
    16501688    }
     1689    else
     1690        timecode = audio.GetAudioTime();
    16511691
    16521692    float diverge = 0.0f;
    16531693    int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval;
     1694    int vsync_delay_clock = 0;
     1695    int64_t currentaudiotime = 0;
    16541696
    16551697    // attempt to reduce fps for standalone PIP
    16561698    if (player_ctx->IsPIP() && framesPlayed % 2)
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    16801722    if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
    16811723        ps = kScan_Progressive;
    16821724
     1725    bool dropframe = false;
     1726    QString dbg;
     1727
     1728    if (avsync_predictor_enabled) // && !prebuffering)
     1729    {
     1730        avsync_predictor += frame_interval;
     1731        if (avsync_predictor >= refreshrate)
     1732        {
     1733            int refreshperiodsinframe = avsync_predictor/refreshrate;
     1734            avsync_predictor -= refreshrate * refreshperiodsinframe;
     1735        }
     1736        else
     1737        {
     1738            dropframe = true;
     1739            dbg = "A/V predict drop frame, ";
     1740        }
     1741    }
     1742
    16831743    if (diverge < -MAXDIVERGE)
    16841744    {
     1745        dropframe = true;
    16851746        // If video is way behind of audio, adjust for it...
    1686         QString dbg = QString("Video is %1 frames behind audio (too slow), ")
     1747        dbg = QString("Video is %1 frames behind audio (too slow), ")
    16871748            .arg(-diverge);
     1749    }
    16881750
     1751    if (dropframe)
     1752    {
    16891753        // Reset A/V Sync
    16901754        lastsync = true;
    16911755
     1756        currentaudiotime = AVSyncGetAudiotime();
    16921757        if (!using_null_videoout &&
    16931758            videoOutput->hasHWAcceleration() &&
    16941759           !videoOutput->IsSyncLocked())
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    17121777        // if we get here, we're actually going to do video output
    17131778        videoOutput->PrepareFrame(buffer, ps, osd);
    17141779
    1715         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
     1780        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("AVSync waitforframe %1 %2")
    17161781                .arg(avsync_adjustment).arg(m_double_framerate));
    1717         videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay);
    1718         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
     1782        vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay);
     1783        currentaudiotime = AVSyncGetAudiotime();
     1784        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + "AVSync show");
    17191785        videoOutput->Show(ps);
    17201786
    17211787        if (videoOutput->IsErrored())
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    17431809            videoOutput->PrepareFrame(buffer, ps, osd);
    17441810
    17451811            // Display the second field
    1746             videosync->WaitForFrame(frameDelay + avsync_adjustment);
     1812            //videosync->AdvanceTrigger();
     1813            vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment);
    17471814            videoOutput->Show(ps);
    17481815        }
    17491816
    17501817        repeat_delay = frame_interval * repeat_pict * 0.5;
    17511818
    17521819        if (repeat_delay)
    1753             VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
     1820            VERBOSE(VB_TIMESTAMP, LOC + QString("A/V repeat_pict, adding %1 repeat "
    17541821                    "delay").arg(repeat_delay));
    17551822    }
    17561823    else
    17571824    {
    1758         videosync->WaitForFrame(frameDelay);
     1825        vsync_delay_clock = videosync->WaitForFrame(frameDelay);
     1826        currentaudiotime = AVSyncGetAudiotime();
    17591827    }
    17601828
    17611829    if (output_jmeter)
    1762         output_jmeter->RecordCycleTime();
     1830    {
     1831        if (output_jmeter->RecordCycleTime())
     1832        {
     1833            VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V avsync_delay: %1, "
     1834                    "avsync_avg: %2")
     1835                    .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
     1836                    );
     1837        }
     1838    }
    17631839
    17641840    avsync_adjustment = 0;
    17651841
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    17671843    {
    17681844        // If audio is way behind of video, adjust for it...
    17691845        // by cutting the frame rate in half for the length of this frame
    1770         avsync_adjustment = refreshrate;
     1846        //avsync_adjustment = refreshrate;
     1847        avsync_adjustment = frame_interval;
    17711848        lastsync = true;
    17721849        VERBOSE(VB_PLAYBACK, LOC +
    17731850                QString("Video is %1 frames ahead of audio,\n"
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    17761853
    17771854    if (audio.HasAudioOut() && normal_speed)
    17781855    {
     1856        // must be sampled here due to Show delays
    17791857        int64_t currentaudiotime = audio.GetAudioTime();
    1780         VERBOSE(VB_TIMESTAMP, QString(
     1858        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString(
    17811859                    "A/V timecodes audio %1 video %2 frameinterval %3 "
    1782                     "avdel %4 avg %5 tcoffset %6")
     1860                    "avdel %4 avg %5 tcoffset %6"
     1861                    " avp %7 avpen %8"
     1862                    " avdc %9"
     1863                    )
    17831864                .arg(currentaudiotime)
    17841865                .arg(timecode)
    17851866                .arg(frame_interval)
    1786                 .arg(timecode - currentaudiotime)
     1867                .arg(timecode - currentaudiotime - (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000)
    17871868                .arg(avsync_avg)
    17881869                .arg(tc_wrap[TC_AUDIO])
     1870                .arg(avsync_predictor)
     1871                .arg(avsync_predictor_enabled)
     1872                .arg(vsync_delay_clock)
    17891873                 );
    17901874        if (currentaudiotime != 0 && timecode != 0)
    17911875        { // currentaudiotime == 0 after a seek
    17921876            // The time at the start of this frame (ie, now) is given by
    17931877            // last->timecode
    1794             int delta = (int)((timecode - prevtc)/play_speed) - (frame_interval / 1000);
    1795             prevtc = timecode;
    1796             //cerr << delta << " ";
    1797 
    1798             // If the timecode is off by a frame (dropped frame) wait to sync
    1799             if (delta > (int) frame_interval / 1200 &&
    1800                 delta < (int) frame_interval / 1000 * 3 &&
    1801                 prevrp == 0)
     1878            if (prevtc != 0)
    18021879            {
    1803                 // wait an extra frame interval
    1804                 avsync_adjustment += frame_interval;
     1880                int delta = (int)((timecode - prevtc)/play_speed) - (frame_interval / 1000);
     1881                // If the timecode is off by a frame (dropped frame) wait to sync
     1882                if (delta > (int) frame_interval / 1200 &&
     1883                    delta < (int) frame_interval / 1000 * 3 &&
     1884                    prevrp == 0)
     1885                {
     1886                    // wait an extra frame interval
     1887                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V delay %1").arg(delta));
     1888                    avsync_adjustment += frame_interval;
     1889                    //videosync->AdvanceTrigger();
     1890                    //if (m_double_framerate)
     1891                    //    videosync->AdvanceTrigger();
     1892                }
    18051893            }
     1894            prevtc = timecode;
    18061895            prevrp = repeat_pict;
    18071896
    1808             avsync_delay = (timecode - currentaudiotime) * 1000;//usec
     1897            avsync_delay = (timecode - currentaudiotime) * 1000 - (int)(vsync_delay_clock*audio.GetStretchFactor());  //usec
    18091898            // prevents major jitter when pts resets during dvd title
    18101899            if (avsync_delay > 2000000 && limit_delay)
    18111900                avsync_delay = 90000;
    18121901            avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;
    18131902
     1903            int avsync_used = avsync_avg;
     1904            if (labs(avsync_used) > labs(avsync_delay))
     1905                avsync_used = avsync_delay;
     1906
    18141907            /* If the audio time codes and video diverge, shift
    18151908               the video by one interlaced field (1/2 frame) */
    18161909            if (!lastsync)
    18171910            {
    1818                 if (avsync_avg > frame_interval * 3 / 2)
     1911                if (avsync_used > refreshrate)
    18191912                {
    18201913                    avsync_adjustment += refreshrate;
    1821                     lastsync = true;
     1914                    //lastsync = true;
     1915                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high extend");
    18221916                }
    1823                 else if (avsync_avg < 0 - frame_interval * 3 / 2)
     1917                else if (avsync_used < 0 - refreshrate)
    18241918                {
    18251919                    avsync_adjustment -= refreshrate;
    1826                     lastsync = true;
     1920                    //lastsync = true;
     1921                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high skip");
    18271922                }
    18281923            }
    18291924            else
    void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)  
    18311926        }
    18321927        else
    18331928        {
    1834             avsync_avg = 0;
     1929            ResetAVSync();
    18351930        }
    18361931    }
     1932    else
     1933    {
     1934        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V no sync proc ns:%1").arg(normal_speed));
     1935    }
    18371936}
    18381937
    18391938void MythPlayer::DisplayPauseFrame(void)
    void MythPlayer::ClearAfterSeek(bool clearvideobuffers)  
    34373536    commBreakMap.SetTracker(framesPlayed);
    34383537    commBreakMap.ResetLastSkip();
    34393538    needNewPauseFrame = true;
     3539    ResetAVSync();
    34403540}
    34413541
    34423542void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget,
  • mythtv/libs/libmythtv/mythplayer.h

    diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
    index 95a4883..88d4d79 100644
    a b class MPUBLIC MythPlayer  
    509509    void  WrapTimecode(int64_t &timecode, TCTypes tc_type);
    510510    void  InitAVSync(void);
    511511    virtual void AVSync(VideoFrame *buffer, bool limit_delay = false);
     512    void  ResetAVSync(void);
     513    int64_t AVSyncGetAudiotime(void);
     514    void  SetFrameInterval(FrameScanType scan, double speed);
    512515    void  FallbackDeint(void);
    513516    void  CheckExtraAudioDecode(void);
    514517
    class MPUBLIC MythPlayer  
    694697    int        avsync_delay;
    695698    int        avsync_adjustment;
    696699    int        avsync_avg;
     700    int        avsync_predictor;
     701    bool       avsync_predictor_enabled;
    697702    int        refreshrate;
    698703    bool       lastsync;
    699704    bool       decode_extra_audio;