Ticket #11371: 0001-DVD-PTS-discontinuities-are-now-handled-by-flattenin.patch

File 0001-DVD-PTS-discontinuities-are-now-handled-by-flattenin.patch, 11.2 KB (added by peper03@…, 11 years ago)

New patch that flattens DVD timestamps to avoid PTS jumps.

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

    From 24b0b0197a777c801e681beba5aff9a39f5283fc Mon Sep 17 00:00:00 2001
    From: Richard <peper03@yahoo.com>
    Date: Fri, 1 Mar 2013 22:13:21 +0100
    Subject: [PATCH] DVD PTS discontinuities are now handled by 'flattening' the
     timecodes of incoming packets.  This prevents
     AVFormatDecoder getting stuck buffering video frames when
     the timecodes jump backwards.
    
    ---
     mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp |   42 +++++++++++++
     mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h   |    4 ++
     mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp      |   71 ++++++++++++++++++----
     mythtv/libs/libmythtv/DVD/dvdringbuffer.h        |   18 ++++++
     mythtv/libs/libmythtv/avformatdecoder.cpp        |    7 ++-
     mythtv/libs/libmythtv/avformatdecoder.h          |    3 +
     6 files changed, 133 insertions(+), 12 deletions(-)
    
    diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
    index a27dfe5..ce7731b 100644
    a b bool AvFormatDecoderDVD::GetFrame(DecodeType decodetype) 
    3232    return AvFormatDecoder::GetFrame( kDecodeAV );
    3333}
    3434
     35int64_t AvFormatDecoderDVD::AdjustTimestamp(int64_t timestamp)
     36{
     37    int64_t newTimestamp = timestamp;
     38
     39    if (newTimestamp != AV_NOPTS_VALUE)
     40    {
     41        int64_t timediff = ringBuffer->DVD()->GetTimeDiff();
     42        if (newTimestamp >= timediff)
     43        {
     44            newTimestamp -= timediff;
     45        }
     46    }
     47
     48    return newTimestamp;
     49}
     50
     51int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt)
     52{
     53    int result = av_read_frame(ctx, pkt);
     54
     55    while (result == AVERROR_EOF && errno == EAGAIN)
     56    {
     57        if (ringBuffer->DVD()->IsReadingBlocked())
     58        {
     59            ringBuffer->DVD()->UnblockReading();
     60            result = av_read_frame(ctx, pkt);
     61        }
     62        else
     63        {
     64            break;
     65        }
     66    }
     67
     68    if (result >= 0)
     69    {
     70        pkt->dts = AdjustTimestamp(pkt->dts);
     71        pkt->pts = AdjustTimestamp(pkt->pts);
     72    }
     73
     74    return result;
     75}
     76
    3577void AvFormatDecoderDVD::PostProcessTracks(void)
    3678{
    3779    if (!ringBuffer)
  • mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h

    diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
    index 1b15425..bdb64e4 100644
    a b class AvFormatDecoderDVD : public AvFormatDecoder 
    1212    virtual void UpdateFramesPlayed(void);
    1313    virtual bool GetFrame(DecodeType decodetype); // DecoderBase
    1414
     15  protected:
     16    int64_t AdjustTimestamp(int64_t timestamp);
     17    virtual int  ReadPacket(AVFormatContext *ctx, AVPacket *pkt);
     18
    1519  private:
    1620    virtual bool DoRewindSeek(long long desiredFrame);
    1721    virtual void DoFastForwardSeek(long long desiredFrame, bool &needflush);
  • mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp

    diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
    index b0fa1ae..2698142 100644
    a b DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : 
    8989    m_lastNav(NULL),    m_part(0), m_lastPart(0),
    9090    m_title(0),         m_lastTitle(0),   m_playerWait(false),
    9191    m_titleParts(0),    m_gotStop(false), m_currentAngle(0),
    92     m_currentTitleAngleCount(0), m_newSequence(false),
     92    m_currentTitleAngleCount(0),
     93    m_endPts(0),        m_timeDiff(0),
     94    m_newSequence(false),
    9395    m_still(0), m_lastStill(0),
    9496    m_audioStreamsChanged(false),
    9597    m_dvdWaiting(false),
    DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : 
    109111    m_currentTime(0),
    110112    m_parent(NULL),
    111113    m_forcedAspect(-1.0f),
     114    m_processState(PROCESS_NORMAL),
     115    m_dvdStat(DVDNAV_STATUS_OK),
     116    m_dvdEvent(0),
     117    m_dvdEventSize(0),
    112118
    113119    // Menu/buttons
    114120    m_inMenu(false), m_buttonVersion(1), m_buttonStreamID(0),
    bool DVDRingBuffer::StartFromBeginning(void) 
    397403        m_audioStreamsChanged = true;
    398404    }
    399405
     406    m_endPts = 0;
     407    m_timeDiff = 0;
     408
    400409    return m_dvdnav;
    401410}
    402411
    void DVDRingBuffer::WaitForPlayer(void) 
    486495
    487496int DVDRingBuffer::safe_read(void *data, uint sz)
    488497{
    489     dvdnav_status_t dvdStat;
    490498    unsigned char  *blockBuf     = NULL;
    491499    uint            tot          = 0;
    492     int32_t         dvdEvent     = 0;
    493     int32_t         dvdEventSize = 0;
    494500    int             needed       = sz;
    495501    char           *dest         = (char*) data;
    496502    int             offset       = 0;
     503    bool            bReprocessing = false;
    497504
    498505    if (m_gotStop)
    499506    {
    int DVDRingBuffer::safe_read(void *data, uint sz) 
    505512    if (readaheadrunning)
    506513        LOG(VB_GENERAL, LOG_ERR, LOC + "read ahead thread running.");
    507514
    508     while (needed)
     515    while ((m_processState != PROCESS_WAIT) && needed)
    509516    {
    510517        blockBuf = m_dvdBlockWriteBuf;
    511518
    512         dvdStat = dvdnav_get_next_cache_block(
    513             m_dvdnav, &blockBuf, &dvdEvent, &dvdEventSize);
     519        if (m_processState == PROCESS_REPROCESS)
     520        {
     521            m_processState = PROCESS_NORMAL;
     522            bReprocessing = true;
     523        }
     524        else
     525        {
     526            m_dvdStat = dvdnav_get_next_cache_block(
     527                m_dvdnav, &blockBuf, &m_dvdEvent, &m_dvdEventSize);
    514528
    515         if (dvdStat == DVDNAV_STATUS_ERR)
     529            bReprocessing = false;
     530        }
     531
     532        if (m_dvdStat == DVDNAV_STATUS_ERR)
    516533        {
    517534            LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to read block: %1")
    518535                    .arg(dvdnav_err_to_string(m_dvdnav)));
    int DVDRingBuffer::safe_read(void *data, uint sz) 
    520537            return -1;
    521538        }
    522539
    523         switch (dvdEvent)
     540        switch (m_dvdEvent)
    524541        {
    525542            // Standard packet for decoding
    526543            case DVDNAV_BLOCK_OK:
    int DVDRingBuffer::safe_read(void *data, uint sz) 
    729746            {
    730747                QMutexLocker lock(&m_seekLock);
    731748
     749                pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
     750
     751                // If the start PTS of this block is not the
     752                // same as the end PTS of the last block,
     753                // we've got a timestamp discontinuity
     754                int64_t diff = (int64_t)pci->pci_gi.vobu_s_ptm - m_endPts;
     755                if (diff != 0)
     756                {
     757                    if (!bReprocessing && !m_skipstillorwait)
     758                    {
     759                        LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
     760                            .arg(pci->pci_gi.vobu_s_ptm)
     761                            .arg(m_endPts)
     762                            .arg(diff));
     763
     764                        m_processState = PROCESS_WAIT;
     765                        break;
     766                    }
     767
     768                    m_timeDiff += diff;
     769                }
     770
     771                m_endPts = pci->pci_gi.vobu_e_ptm;
     772
    732773                // get the latest nav
    733774                m_lastNav = (dvdnav_t *)blockBuf;
    734775
    int DVDRingBuffer::safe_read(void *data, uint sz) 
    941982            default:
    942983            {
    943984                LOG(VB_GENERAL, LOG_ERR, LOC +
    944                     QString("Unknown DVD event: %1").arg(dvdEvent));
     985                    QString("Unknown DVD event: %1").arg(m_dvdEvent));
    945986            }
    946987            break;
    947988        }
    int DVDRingBuffer::safe_read(void *data, uint sz) 
    950991        offset = tot;
    951992    }
    952993
    953     return tot;
     994    if (m_processState == PROCESS_WAIT)
     995    {
     996        errno = EAGAIN;
     997        return 0;
     998    }
     999    else
     1000    {
     1001        return tot;
     1002    }
    9541003}
    9551004
    9561005bool DVDRingBuffer::playTrack(int track)
  • mythtv/libs/libmythtv/DVD/dvdringbuffer.h

    diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h
    index 3a31c1b..5468db7 100644
    a b class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    7878    bool IsWaiting(void) const           { return m_dvdWaiting;          }
    7979    int  NumPartsInTitle(void)     const { return m_titleParts;          }
    8080    void GetMenuSPUPkt(uint8_t *buf, int len, int stream_id);
     81    int64_t GetTimeDiff(void)      const { return m_timeDiff; }
    8182
    8283    // Public menu/button stuff
    8384    AVSubtitle *GetMenuSubtitle(uint &version);
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    119120    void SkipStillFrame(void);
    120121    void WaitSkip(void);
    121122    void SkipDVDWaitingForPlayer(void)    { m_playerWait = false;           }
     123    void UnblockReading(void)             { m_processState = PROCESS_REPROCESS; }
     124    bool IsReadingBlocked(void)           { return (m_processState == PROCESS_WAIT); }
    122125    bool GoToMenu(const QString str);
    123126    void GoToNextProgram(void);
    124127    void GoToPreviousProgram(void);
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    137140    void SetParent(MythDVDPlayer *p) { m_parent = p; }
    138141
    139142  protected:
     143
     144    typedef enum
     145    {
     146        PROCESS_NORMAL,
     147        PROCESS_REPROCESS,
     148        PROCESS_WAIT
     149    }processState_t;
     150
    140151    dvdnav_t      *m_dvdnav;
    141152    unsigned char  m_dvdBlockWriteBuf[DVD_BLOCK_SIZE];
    142153    unsigned char *m_dvdBlockReadBuf;
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    159170    bool           m_gotStop;
    160171    int            m_currentAngle;
    161172    int            m_currentTitleAngleCount;
     173    int64_t        m_endPts;
     174    int64_t        m_timeDiff;
    162175
    163176    bool           m_newSequence;
    164177    int            m_still;
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    191204    MythDVDPlayer *m_parent;
    192205    float          m_forcedAspect;
    193206
     207    processState_t  m_processState;
     208    dvdnav_status_t m_dvdStat;
     209    int32_t        m_dvdEvent;
     210    int32_t        m_dvdEventSize;
     211
    194212    // Private menu/button stuff
    195213    void ActivateButton(void);
    196214    void MoveButtonLeft(void);
  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 3e3ce96..d4f6013 100644
    a b bool AvFormatDecoder::GetFrame(DecodeType decodetype) 
    46464646            }
    46474647
    46484648            int retval = 0;
    4649             if (!ic || ((retval = av_read_frame(ic, pkt)) < 0))
     4649            if (!ic || ((retval = ReadPacket(ic, pkt)) < 0))
    46504650            {
    46514651                if (retval == -EAGAIN)
    46524652                    continue;
    bool AvFormatDecoder::GetFrame(DecodeType decodetype) 
    48214821    return true;
    48224822}
    48234823
     4824int AvFormatDecoder::ReadPacket(AVFormatContext *ctx, AVPacket *pkt)
     4825{
     4826    return av_read_frame(ctx, pkt);
     4827}
     4828
    48244829bool AvFormatDecoder::HasVideo(const AVFormatContext *ic)
    48254830{
    48264831    if (ic && ic->cur_pmt_sect)
  • mythtv/libs/libmythtv/avformatdecoder.h

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
    index 379dc96..ea08fc9 100644
    a b class AvFormatDecoder : public DecoderBase 
    264264
    265265    int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size,
    266266                    AVPacket *pkt);
     267
     268    virtual int ReadPacket(AVFormatContext *ctx, AVPacket* pkt);
     269
    267270    PrivateDecoder *private_dec;
    268271
    269272    bool is_db_ignored;