Ticket #11579: 0003-Added-more-consistent-handling-of-slide-shows-i.e.-i.patch

File 0003-Added-more-consistent-handling-of-slide-shows-i.e.-i.patch, 14.8 KB (added by peper03@…, 8 years ago)
  • mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c

    From 353edb23579df46e8acc299fb87e0cfd1d2c1665 Mon Sep 17 00:00:00 2001
    From: Richard <peper03@yahoo.com>
    Date: Mon, 8 Apr 2013 16:37:33 +0200
    Subject: [PATCH 3/4] Added more consistent handling of slide shows (i.e.
     individual video frames to be shown until the next
     video frame appears in the stream).  This allows
     correct playback of still frames with or without audio
     regardless of domain (previously still frames with
     audio was only handled in a menu), so this change
     allows audio DVDs to be played.
    
    ---
     mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c         |    7 +-
     mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp |  134 +++++++++++++++++++---
     mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h   |    2 +
     mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp      |   43 ++++---
     mythtv/libs/libmythtv/DVD/dvdringbuffer.h        |    6 +-
     mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp      |   13 ---
     mythtv/libs/libmythtv/avformatdecoder.cpp        |    7 --
     7 files changed, 156 insertions(+), 56 deletions(-)
    
    diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c
    index f531ade..24e6fd8 100644
    a b void vm_position_get(vm_t *vm, vm_position_t *position) { 
    472472  /* still already determined */
    473473  if (position->still)
    474474    return;
     475#if 0   /* MythTV - Disable this workaround as it is invalid. VOBUs consisting
     476           of just a NAV packet are valid */
    475477  /* This is a rough fix for some strange still situations on some strange DVDs.
    476478   * There are discs (like the German "Back to the Future" RC2) where the only
    477479   * indication of a still is a cell playback time higher than the time the frames
    void vm_position_get(vm_t *vm, vm_position_t *position) { 
    499501    if (time > 0xff) time = 0xff;
    500502    position->still = time;
    501503  }
     504#endif
    502505}
    503506
    504507void vm_get_next_cell(vm_t *vm) {
    static link_t play_Cell(vm_t *vm) { 
    11511154  /* Multi angle/Interleaved */
    11521155  switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
    11531156  case 0: /*  Normal */
    1154     assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
     1157    /*assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);*/
    11551158    break;
    11561159  case 1: /*  The first cell in the block */
    11571160    switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
    static link_t play_Cell_post(vm_t *vm) { 
    12521255  /* Multi angle/Interleaved */
    12531256  switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
    12541257  case 0: /*  Normal */
    1255     assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
     1258    /* assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); */
    12561259    (vm->state).cellN++;
    12571260    break;
    12581261  case 1: /*  The first cell in the block */
  • mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp

    diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
    index b802e31..f4a63c0 100644
    a b AvFormatDecoderDVD::AvFormatDecoderDVD( 
    1212    MythPlayer *parent, const ProgramInfo &pginfo, PlayerFlags flags)
    1313  : AvFormatDecoder(parent, pginfo, flags)
    1414  , m_curContext(NULL)
     15  , m_lastVideoPkt(NULL)
     16  , m_framesReq(0)
    1517{
    1618}
    1719
    AvFormatDecoderDVD::~AvFormatDecoderDVD() 
    2224
    2325    while (m_contextList.size() > 0)
    2426        m_contextList.takeFirst()->DecrRef();
     27
     28    if (m_lastVideoPkt)
     29    {
     30        av_free_packet(m_lastVideoPkt);
     31        delete m_lastVideoPkt;
     32    }
    2533}
    2634
    2735void AvFormatDecoderDVD::Reset(bool reset_video_data, bool seek_reset, bool reset_file)
    bool AvFormatDecoderDVD::GetFrame(DecodeType decodetype) 
    4856
    4957int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt)
    5058{
    51     int result = av_read_frame(ctx, pkt);
     59    int result = 0;
    5260
    53     while (result == AVERROR_EOF && errno == EAGAIN)
     61    if (m_framesReq > 0)
    5462    {
    55         if (ringBuffer->DVD()->IsReadingBlocked())
     63        m_framesReq--;
     64        av_copy_packet(pkt, m_lastVideoPkt);
     65
     66        if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
     67            m_lastVideoPkt->pts += pkt->duration;
     68
     69        if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
     70            m_lastVideoPkt->dts += pkt->duration;
     71    }
     72    else
     73    {
     74        result = av_read_frame(ctx, pkt);
     75
     76        while (result == AVERROR_EOF && errno == EAGAIN)
    5677        {
    57             ringBuffer->DVD()->UnblockReading();
    58             result = av_read_frame(ctx, pkt);
     78            if (ringBuffer->DVD()->IsReadingBlocked())
     79            {
     80                ringBuffer->DVD()->UnblockReading();
     81                result = av_read_frame(ctx, pkt);
     82            }
     83            else
     84            {
     85                break;
     86            }
    5987        }
    60         else
     88
     89        if (result >= 0)
    6190        {
    62             break;
     91            pkt->dts = ringBuffer->DVD()->AdjustTimestamp(pkt->dts);
     92            pkt->pts = ringBuffer->DVD()->AdjustTimestamp(pkt->pts);
    6393        }
    64     }
    6594
    66     if (result >= 0)
    67     {
    68         pkt->dts = ringBuffer->DVD()->AdjustTimestamp(pkt->dts);
    69         pkt->pts = ringBuffer->DVD()->AdjustTimestamp(pkt->pts);
     95        AVStream *curstream = ic->streams[pkt->stream_index];
     96        if(curstream->codec->codec_type == AVMEDIA_TYPE_DATA)
     97        {
     98            LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "Read DVD context @ %1 - curcontext %2 lastVideo %3 reqFrames %4")
     99                .arg(pkt->pts)
     100                .arg((uint64_t)m_curContext, 0, 16)
     101                .arg((uint64_t)m_lastVideoPkt, 0, 16)
     102                .arg(m_framesReq));
     103        }
    70104    }
    71105
    72106    return result;
    void AvFormatDecoderDVD::CheckContext(int64_t pts) 
    98132                m_curContext->DecrRef();
    99133
    100134            m_curContext = m_contextList.takeFirst();
     135
     136            LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "New DVD context @ %1 - %2")
     137                .arg(pts)
     138                .arg(m_curContext->GetNumFramesPresent()));
     139
     140            if (m_curContext->GetNumFramesPresent() == 0)
     141            {
     142                // No video frames present, so we need to generate
     143                // them based on the last 'sequence end' video packet.
     144                m_framesReq = m_curContext->GetNumFrames();
     145            }
     146            else
     147            {
     148                m_framesReq = 0;
     149                if (m_lastVideoPkt)
     150                {
     151                    av_free_packet(m_lastVideoPkt);
     152                    delete m_lastVideoPkt;
     153                    m_lastVideoPkt = NULL;
     154                }
     155            }
    101156        }
    102157    }
    103158}
    bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt) 
    112167
    113168    CheckContext(pts);
    114169
    115     return AvFormatDecoder::ProcessVideoPacket(stream, pkt);
     170    bool ret = AvFormatDecoder::ProcessVideoPacket(stream, pkt);
     171       
     172    if( ret &&
     173        m_curContext &&
     174        pts != AV_NOPTS_VALUE &&
     175        pts + pkt->duration == m_curContext->GetSeqEndPTS())
     176    {
     177        // If this video frame is the last in the sequence,
     178        // make a copy of it so we can 'generate' more
     179        // to fill in the gaps (e.g. when a single frame
     180        // should be displayed with audio)
     181        if (!m_lastVideoPkt)
     182        {
     183            m_lastVideoPkt = new AVPacket;
     184            memset(m_lastVideoPkt, 0, sizeof(AVPacket));
     185        }
     186        else
     187        {
     188            av_free_packet(m_lastVideoPkt);
     189        }
     190
     191        av_init_packet(m_lastVideoPkt);
     192        av_copy_packet(m_lastVideoPkt, pkt);
     193
     194        if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
     195            m_lastVideoPkt->pts += pkt->duration;
     196
     197        if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
     198            m_lastVideoPkt->dts += pkt->duration;
     199
     200        m_framesReq = m_curContext->GetNumFrames() - m_curContext->GetNumFramesPresent();
     201
     202        LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "SeqEnd @ %1 - require %2 frame(s)")
     203            .arg(pkt->pts)
     204            .arg(m_framesReq));
     205    }
     206
     207    return ret;
    116208}
    117209
    118210bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt,
    bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt, 
    126218
    127219        if (context)
    128220            m_contextList.append(context);
     221
     222        if (m_curContext == NULL)
     223        {
     224            // If we don't have a current context, use
     225            // the first in the list
     226            CheckContext(m_contextList.first()->GetStartPTS());
     227        }
     228        else
     229        if (m_lastVideoPkt)
     230        {
     231            // If we've been generating frames, see whether this
     232            // new context should be used already (handles
     233            // situations where a VOBU consists of only a NAV
     234            // packet and nothing else)
     235            CheckContext(m_lastVideoPkt->pts);
     236        }
    129237    }
    130238    else
    131239    {
  • mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h

    diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
    index 7a167f0..00de975 100644
    a b class AvFormatDecoderDVD : public AvFormatDecoder 
    3636
    3737    MythDVDContext*        m_curContext;
    3838    QList<MythDVDContext*> m_contextList;
     39    AVPacket*              m_lastVideoPkt;
     40    int                    m_framesReq;
    3941};
    4042
    4143#endif // AVFORMATDECODERDVD_H
  • mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp

    diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
    index c023d73..2bf1088 100644
    a b MythDVDContext::~MythDVDContext() 
    8787{
    8888}
    8989
     90int MythDVDContext::GetNumFrames() const
     91{
     92    return ((GetEndPTS() - GetStartPTS()) * GetFPS()) / 90000;
     93}
     94
     95int MythDVDContext::GetNumFramesPresent() const
     96{
     97    int frames = 0;
     98
     99    if (GetSeqEndPTS())
     100    {
     101        // Sequence end PTS is set.  This means that video frames
     102        // are not present all the way to 'End PTS'
     103        frames = ((GetSeqEndPTS() - GetStartPTS()) * GetFPS()) / 90000;
     104    }
     105    else
     106    if (m_dsi.dsi_gi.vobu_1stref_ea != 0)
     107    {
     108        // At least one video frame is present
     109        frames = GetNumFrames();
     110    }
     111
     112    return frames;
     113}
     114
    90115DVDRingBuffer::DVDRingBuffer(const QString &lfilename) :
    91116    RingBuffer(kRingBuffer_DVD),
    92117    m_dvdnav(NULL),     m_dvdBlockReadBuf(NULL),
    DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : 
    100125    m_titleParts(0),    m_gotStop(false), m_currentAngle(0),
    101126    m_currentTitleAngleCount(0),
    102127    m_endPts(0),        m_timeDiff(0),
    103     m_newSequence(false),
    104128    m_still(0), m_lastStill(0),
    105129    m_audioStreamsChanged(false),
    106130    m_dvdWaiting(false),
    bool DVDRingBuffer::SwitchAngle(uint angle) 
    20542078    }
    20552079    return false;
    20562080}
    2057 
    2058 bool DVDRingBuffer::NewSequence(bool new_sequence)
    2059 {
    2060     bool result = false;
    2061     if (new_sequence)
    2062     {
    2063         LOG(VB_PLAYBACK, LOG_INFO, LOC + "New sequence");
    2064         m_newSequence = true;
    2065         return result;
    2066     }
    2067 
    2068     result = m_newSequence && m_inMenu;
    2069     m_newSequence = false;
    2070     if (result)
    2071         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Asking for still frame");
    2072     return result;
    2073 }
  • mythtv/libs/libmythtv/DVD/dvdringbuffer.h

    diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h
    index a331d4a..42e1cfc 100644
    a b class MTV_PUBLIC MythDVDContext : public ReferenceCounter 
    3131    int64_t  GetEndPTS()           const { return (int64_t)m_pci.pci_gi.vobu_e_ptm;    }
    3232    int64_t  GetSeqEndPTS()        const { return (int64_t)m_pci.pci_gi.vobu_se_e_ptm; }
    3333    uint32_t GetLBA()              const { return m_pci.pci_gi.nv_pck_lbn;             }
     34    int      GetNumFrames()        const;
     35    int      GetNumFramesPresent() const;
     36    int      GetFPS()              const { return (m_pci.pci_gi.e_eltm.frame_u & 0x80) ? 30 : 25; }
    3437
    3538  protected:
    3639    MythDVDContext();
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    9396    bool PGCLengthChanged(void);
    9497    bool CellChanged(void);
    9598    virtual bool IsInStillFrame(void)   const { return m_still > 0;             }
    96     bool NeedsStillFrame(void) { return IsInStillFrame() || NewSequence(); }
    97     bool NewSequence(bool new_sequence = false);
    9899    bool AudioStreamsChanged(void) const { return m_audioStreamsChanged; }
    99100    bool IsWaiting(void) const           { return m_dvdWaiting;          }
    100101    int  NumPartsInTitle(void)     const { return m_titleParts;          }
    class MTV_PUBLIC DVDRingBuffer : public RingBuffer 
    198199    int64_t        m_endPts;
    199200    int64_t        m_timeDiff;
    200201
    201     bool           m_newSequence;
    202202    int            m_still;
    203203    int            m_lastStill;
    204204    bool           m_audioStreamsChanged;
  • mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp

    diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp b/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp
    index 2cf7b37..34aa40b 100644
    a b bool MythDVDPlayer::VideoLoop(void) 
    177177            return !IsErrored();
    178178        }
    179179
    180         // we need a custom presentation method for still frame menus with audio
    181         if (player_ctx->buffer->DVD()->IsInMenu() &&
    182             !player_ctx->buffer->DVD()->IsInStillFrame())
    183         {
    184             // ensure we refresh the pause frame
    185             if (!dvd_stillframe_showing)
    186                 needNewPauseFrame = true;
    187             RefreshPauseFrame();
    188             dvd_stillframe_showing = true;
    189             DisplayLastFrame();
    190             return !IsErrored();
    191         }
    192 
    193180        // the still frame is treated as a pause frame
    194181        if (player_ctx->buffer->DVD()->IsInStillFrame())
    195182        {
  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index c6986e6..f3b944e 100644
    a b void AvFormatDecoder::MpegPreProcessPkt(AVStream *stream, AVPacket *pkt) 
    30103010
    30113011        float aspect_override = -1.0f;
    30123012        if (ringBuffer->IsDVD())
    3013         {
    3014             if (start_code_state == SEQ_END_CODE)
    3015                 ringBuffer->DVD()->NewSequence(true);
    30163013            aspect_override = ringBuffer->DVD()->GetAspectOverride();
    3017         }
    30183014
    30193015        if (start_code_state >= SLICE_MIN && start_code_state <= SLICE_MAX)
    30203016            continue;
    bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt) 
    33093305    {
    33103306        context->reordered_opaque = pkt->pts;
    33113307        ret = avcodec_decode_video2(context, &mpa_pic, &gotpicture, pkt);
    3312         // Reparse it to not drop the DVD still frame
    3313         if (ringBuffer->IsDVD() && ringBuffer->DVD()->NeedsStillFrame())
    3314             ret = avcodec_decode_video2(context, &mpa_pic, &gotpicture, pkt);
    33153308    }
    33163309    avcodeclock->unlock();
    33173310