Ticket #7964: mythtv_smoothsync.12.patch

File mythtv_smoothsync.12.patch, 12.8 KB (added by Mark Spieth, 14 years ago)
  • mythtv/libs/libmythtv/mythplayer.cpp

    commit 76824fb52cc307efc68674104e3711df100ff71b
    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/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index 42ad109..575bc50 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) 
    15981599    return NextCaptionTrack(nextmode);
    15991600}
    16001601
     1602void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
     1603{
     1604    frame_interval = (int)(1000000.0f * frame_period + 0.5f);
     1605    if (!avsync_predictor_enabled)
     1606        avsync_predictor = 0;
     1607    avsync_predictor_enabled = false;
     1608
     1609    VERBOSE(VB_PLAYBACK, LOC + QString("SetFrameInterval ps:%1 scan:%2")
     1610            .arg(play_speed).arg(scan)
     1611           );
     1612    if (play_speed < 1 || play_speed > 2 || refreshrate <= 0)
     1613        return;
     1614
     1615    avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) < refreshrate);
     1616}
     1617
     1618void MythPlayer::ResetAVSync(void)
     1619{
     1620    avsync_avg = 0;
     1621    if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
     1622        avsync_predictor = 0;
     1623    prevtc = 0;
     1624    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V sync reset");
     1625}
     1626
    16011627void MythPlayer::InitAVSync(void)
    16021628{
    16031629    videosync->Start();
    void MythPlayer::InitAVSync(void) 
    16201646                       .arg(refreshrate).arg(frame_interval);
    16211647        VERBOSE(VB_PLAYBACK, LOC + msg);
    16221648
     1649        SetFrameInterval(m_scan, 1.0 / (video_frame_rate * play_speed));
     1650
    16231651        // try to get preferential scheduling, but ignore if we fail to.
    16241652        myth_nice(-19);
    16251653    }
    16261654}
    16271655
     1656int64_t MythPlayer::AVSyncGetAudiotime(void)
     1657{
     1658    int64_t currentaudiotime = 0;
     1659    if (normal_speed)
     1660    {
     1661        currentaudiotime = audio.GetAudioTime();
     1662    }
     1663    return currentaudiotime;
     1664}
     1665
    16281666#define MAXDIVERGE  3.0f
    16291667#define DIVERGELIMIT 30.0f
    16301668void MythPlayer::AVSync(bool limit_delay)
    16311669{
    16321670    float diverge = 0.0f;
    16331671    int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval;
     1672    int vsync_delay_clock = 0;
     1673    int64_t currentaudiotime = 0;
     1674
    16341675    // attempt to reduce fps for standalone PIP
    16351676    if (player_ctx->IsPIP() && framesPlayed % 2)
    16361677    {
    void MythPlayer::AVSync(bool limit_delay) 
    16651706    if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
    16661707        ps = kScan_Progressive;
    16671708
     1709    bool dropframe = false;
     1710    QString dbg;
     1711
     1712    if (avsync_predictor_enabled) // && !prebuffering)
     1713    {
     1714        avsync_predictor += frame_interval;
     1715        if (avsync_predictor >= refreshrate)
     1716        {
     1717            int refreshperiodsinframe = avsync_predictor/refreshrate;
     1718            avsync_predictor -= refreshrate * refreshperiodsinframe;
     1719        }
     1720        else
     1721        {
     1722            dropframe = true;
     1723            dbg = "A/V predict drop frame, ";
     1724        }
     1725    }
     1726
    16681727    if (diverge < -MAXDIVERGE)
    16691728    {
     1729        dropframe = true;
    16701730        // If video is way behind of audio, adjust for it...
    1671         QString dbg = QString("Video is %1 frames behind audio (too slow), ")
     1731        dbg = QString("Video is %1 frames behind audio (too slow), ")
    16721732            .arg(-diverge);
     1733    }
    16731734
     1735    if (dropframe)
     1736    {
    16741737        // Reset A/V Sync
    16751738        lastsync = true;
    16761739
     1740        currentaudiotime = AVSyncGetAudiotime();
     1741
    16771742        if (buffer && !using_null_videoout &&
    16781743            videoOutput->hasHWAcceleration() &&
    16791744           !videoOutput->IsSyncLocked())
    void MythPlayer::AVSync(bool limit_delay) 
    16981763        if (buffer)
    16991764            videoOutput->PrepareFrame(buffer, ps, osd);
    17001765
    1701         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
     1766        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("AVSync waitforframe %1 %2")
    17021767                .arg(avsync_adjustment).arg(m_double_framerate));
    1703         videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay);
    1704         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
     1768        vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay);
     1769        currentaudiotime = AVSyncGetAudiotime();
     1770        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + "AVSync show");
    17051771        videoOutput->Show(ps);
    17061772
    17071773        if (videoOutput->IsErrored())
    void MythPlayer::AVSync(bool limit_delay) 
    17301796                videoOutput->PrepareFrame(buffer, ps, osd);
    17311797
    17321798            // Display the second field
    1733             videosync->WaitForFrame(frameDelay + avsync_adjustment);
     1799            //videosync->AdvanceTrigger();
     1800            vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment);
    17341801            videoOutput->Show(ps);
    17351802        }
    17361803
    17371804        repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
    17381805
    17391806        if (repeat_delay)
    1740             VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
     1807            VERBOSE(VB_TIMESTAMP, LOC + QString("A/V repeat_pict, adding %1 repeat "
    17411808                    "delay").arg(repeat_delay));
    17421809    }
    17431810    else
    17441811    {
    1745         videosync->WaitForFrame(frameDelay);
     1812        vsync_delay_clock = videosync->WaitForFrame(frameDelay);
     1813        currentaudiotime = AVSyncGetAudiotime();
    17461814    }
    17471815
    17481816    if (output_jmeter)
    1749         output_jmeter->RecordCycleTime();
     1817    {
     1818        if (output_jmeter->RecordCycleTime())
     1819        {
     1820            VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V avsync_delay: %1, "
     1821                    "avsync_avg: %2")
     1822                    .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
     1823                    );
     1824        }
     1825    }
    17501826
    17511827    avsync_adjustment = 0;
    17521828
    void MythPlayer::AVSync(bool limit_delay) 
    17541830    {
    17551831        // If audio is way behind of video, adjust for it...
    17561832        // by cutting the frame rate in half for the length of this frame
    1757         avsync_adjustment = refreshrate;
     1833        //avsync_adjustment = refreshrate;
     1834        avsync_adjustment = frame_interval;
    17581835        lastsync = true;
    17591836        VERBOSE(VB_PLAYBACK, LOC +
    17601837                QString("Video is %1 frames ahead of audio,\n"
    void MythPlayer::AVSync(bool limit_delay) 
    17641841    if (audio.HasAudioOut() && normal_speed)
    17651842    {
    17661843        int64_t currentaudiotime = audio.GetAudioTime();
    1767         VERBOSE(VB_TIMESTAMP, QString(
     1844        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString(
    17681845                    "A/V timecodes audio %1 video %2 frameinterval %3 "
    1769                     "avdel %4 avg %5 tcoffset %6")
     1846                    "avdel %4 avg %5 tcoffset %6"
     1847                    " avp %7 avpen %8"
     1848                    " avdc %9"
     1849                    )
    17701850                .arg(currentaudiotime)
    17711851                .arg(buffer->timecode)
    17721852                .arg(frame_interval)
    1773                 .arg(buffer->timecode - currentaudiotime)
     1853                .arg(buffer->timecode - currentaudiotime - (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000)
    17741854                .arg(avsync_avg)
    17751855                .arg(tc_wrap[TC_AUDIO])
     1856                .arg(avsync_predictor)
     1857                .arg(avsync_predictor_enabled)
     1858                .arg(vsync_delay_clock)
    17761859                 );
    17771860        if (currentaudiotime != 0 && buffer->timecode != 0)
    17781861        { // currentaudiotime == 0 after a seek
    17791862            // The time at the start of this frame (ie, now) is given by
    17801863            // last->timecode
    1781             int delta = (int)((buffer->timecode - prevtc)/play_speed) - (frame_interval / 1000);
    1782             prevtc = buffer->timecode;
    1783             //cerr << delta << " ";
    1784 
    1785             // If the timecode is off by a frame (dropped frame) wait to sync
    1786             if (delta > (int) frame_interval / 1200 &&
    1787                 delta < (int) frame_interval / 1000 * 3 &&
    1788                 prevrp == 0)
     1864            if (prevtc != 0)
    17891865            {
    1790                 // wait an extra frame interval
    1791                 avsync_adjustment += frame_interval;
     1866                int delta = (int)((buffer->timecode - prevtc)/play_speed) - (frame_interval / 1000);
     1867                // If the timecode is off by a frame (dropped frame) wait to sync
     1868                if (delta > (int) frame_interval / 1200 &&
     1869                    delta < (int) frame_interval / 1000 * 3 &&
     1870                    prevrp == 0)
     1871                {
     1872                    // wait an extra frame interval
     1873                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V delay %1").arg(delta));
     1874                    avsync_adjustment += frame_interval;
     1875                    //videosync->AdvanceTrigger();
     1876                    //if (m_double_framerate)
     1877                    //    videosync->AdvanceTrigger();
     1878                }
    17921879            }
     1880            prevtc = buffer->timecode;
    17931881            prevrp = buffer->repeat_pict;
    17941882
    1795             avsync_delay = (buffer->timecode - currentaudiotime) * 1000;//usec
     1883            avsync_delay = (buffer->timecode - currentaudiotime) * 1000 - (int)(vsync_delay_clock*audio.GetStretchFactor());  //usec
    17961884            // prevents major jitter when pts resets during dvd title
    17971885            if (avsync_delay > 2000000 && limit_delay)
    17981886                avsync_delay = 90000;
    17991887            avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;
    18001888
     1889            int avsync_used = avsync_avg;
     1890            if (labs(avsync_used) > labs(avsync_delay))
     1891                avsync_used = avsync_delay;
     1892
    18011893            /* If the audio time codes and video diverge, shift
    18021894               the video by one interlaced field (1/2 frame) */
    18031895            if (!lastsync)
    18041896            {
    1805                 if (avsync_avg > frame_interval * 3 / 2)
     1897                if (avsync_used > refreshrate)
    18061898                {
    18071899                    avsync_adjustment += refreshrate;
    1808                     lastsync = true;
     1900                    //lastsync = true;
     1901                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high extend");
    18091902                }
    1810                 else if (avsync_avg < 0 - frame_interval * 3 / 2)
     1903                else if (avsync_used < 0 - refreshrate)
    18111904                {
    18121905                    avsync_adjustment -= refreshrate;
    1813                     lastsync = true;
     1906                    //lastsync = true;
     1907                    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V avg high skip");
    18141908                }
    18151909            }
    18161910            else
    void MythPlayer::AVSync(bool limit_delay) 
    18181912        }
    18191913        else
    18201914        {
    1821             avsync_avg = 0;
     1915            ResetAVSync();
    18221916        }
    18231917    }
     1918    else
     1919    {
     1920        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString("A/V no sync proc ns:%1").arg(normal_speed));
     1921    }
    18241922}
    18251923
    18261924void MythPlayer::DisplayPauseFrame(void)
    void MythPlayer::ChangeSpeed(void) 
    30663164    }
    30673165
    30683166    float temp_speed = (play_speed == 0.0) ? audio.GetStretchFactor() : play_speed;
    3069     frame_interval = (int) (1000000.0f * ffrew_skip / video_frame_rate /
    3070                             temp_speed);
     3167    SetFrameInterval(m_scan, ffrew_skip / (video_frame_rate * temp_speed));
    30713168
    30723169    VERBOSE(VB_PLAYBACK, LOC + "Play speed: " +
    30733170            QString("rate: %1 speed: %2 skip: %3 => new interval %4")
    void MythPlayer::ClearAfterSeek(bool clearvideobuffers) 
    33503447    commBreakMap.SetTracker(framesPlayed);
    33513448    commBreakMap.ResetLastSkip();
    33523449    needNewPauseFrame = true;
     3450    ResetAVSync();
    33533451}
    33543452
    33553453void 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 e58bb90..602b8a6 100644
    a b class MPUBLIC MythPlayer 
    488488    void  WrapTimecode(int64_t &timecode, TCTypes tc_type);
    489489    void  InitAVSync(void);
    490490    virtual void AVSync(bool limit_delay = false);
     491    void  ResetAVSync(void);
     492    int64_t AVSyncGetAudiotime(void);
     493    void  SetFrameInterval(FrameScanType scan, double speed);
    491494    void  FallbackDeint(void);
    492495    void  CheckExtraAudioDecode(void);
    493496
    class MPUBLIC MythPlayer 
    671674    int        avsync_delay;
    672675    int        avsync_adjustment;
    673676    int        avsync_avg;
     677    int        avsync_predictor;
     678    bool       avsync_predictor_enabled;
    674679    int        refreshrate;
    675680    bool       lastsync;
    676681    bool       decode_extra_audio;