From 5cf7ffe9220b67c4c15f427ce3348d28b48e267c Mon Sep 17 00:00:00 2001
From: Richard <peper03@yahoo.com>
Date: Mon, 8 Apr 2013 20:53:21 +0200
Subject: [PATCH 2/4] Add DVD context class to encapsulate the state of the
DVD VM so that this can be decoupled from the
ringbuffer. As the decoder and player lag the
ringbuffer by up to a second or more, this will allow
them to base their operation on the DVD state at the
time any given frame was read and not on the 'current'
state, which may well not be the same.
This change adds no real functionality but implements the base functionality to be built on in further commits.
---
mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp | 107 ++++++++++++++++++----
mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h | 13 ++-
mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp | 95 ++++++++++++++++++-
mythtv/libs/libmythtv/DVD/dvdringbuffer.h | 28 +++++-
mythtv/libs/libmythtv/avformatdecoder.h | 8 +-
5 files changed, 221 insertions(+), 30 deletions(-)
diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
index 9f12774..b802e31 100644
a
|
b
|
|
2 | 2 | #include "mythdvdplayer.h" |
3 | 3 | #include "avformatdecoderdvd.h" |
4 | 4 | |
| 5 | extern "C" { |
| 6 | #include "libavcodec/avcodec.h" |
| 7 | } |
| 8 | |
5 | 9 | #define LOC QString("AFD_DVD: ") |
6 | 10 | |
7 | 11 | AvFormatDecoderDVD::AvFormatDecoderDVD( |
8 | 12 | MythPlayer *parent, const ProgramInfo &pginfo, PlayerFlags flags) |
9 | 13 | : AvFormatDecoder(parent, pginfo, flags) |
| 14 | , m_curContext(NULL) |
10 | 15 | { |
11 | 16 | } |
12 | 17 | |
| 18 | AvFormatDecoderDVD::~AvFormatDecoderDVD() |
| 19 | { |
| 20 | if (m_curContext) |
| 21 | m_curContext->DecrRef(); |
| 22 | |
| 23 | while (m_contextList.size() > 0) |
| 24 | m_contextList.takeFirst()->DecrRef(); |
| 25 | } |
| 26 | |
13 | 27 | void AvFormatDecoderDVD::Reset(bool reset_video_data, bool seek_reset, bool reset_file) |
14 | 28 | { |
15 | 29 | AvFormatDecoder::Reset(reset_video_data, seek_reset, reset_file); |
… |
… |
bool AvFormatDecoderDVD::GetFrame(DecodeType decodetype) |
32 | 46 | return AvFormatDecoder::GetFrame( kDecodeAV ); |
33 | 47 | } |
34 | 48 | |
35 | | int64_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 | | |
51 | 49 | int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt) |
52 | 50 | { |
53 | 51 | int result = av_read_frame(ctx, pkt); |
… |
… |
int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt) |
67 | 65 | |
68 | 66 | if (result >= 0) |
69 | 67 | { |
70 | | pkt->dts = AdjustTimestamp(pkt->dts); |
71 | | pkt->pts = AdjustTimestamp(pkt->pts); |
| 68 | pkt->dts = ringBuffer->DVD()->AdjustTimestamp(pkt->dts); |
| 69 | pkt->pts = ringBuffer->DVD()->AdjustTimestamp(pkt->pts); |
72 | 70 | } |
73 | 71 | |
74 | 72 | return result; |
75 | 73 | } |
76 | 74 | |
| 75 | void AvFormatDecoderDVD::CheckContext(int64_t pts) |
| 76 | { |
| 77 | if (pts != AV_NOPTS_VALUE) |
| 78 | { |
| 79 | while (m_contextList.size() > 0 && |
| 80 | pts >= m_contextList.first()->GetEndPTS()) |
| 81 | { |
| 82 | if (m_curContext) |
| 83 | m_curContext->DecrRef(); |
| 84 | |
| 85 | m_curContext = m_contextList.takeFirst(); |
| 86 | |
| 87 | LOG(VB_GENERAL, LOG_ERR, LOC + |
| 88 | QString("DVD context missed! lba: %1, curpts: %2, nav end pts: %3") |
| 89 | .arg(m_curContext->GetLBA()) |
| 90 | .arg(pts) |
| 91 | .arg(m_curContext->GetEndPTS())); |
| 92 | } |
| 93 | |
| 94 | if (m_contextList.size() > 0 && |
| 95 | pts >= m_contextList.first()->GetStartPTS()) |
| 96 | { |
| 97 | if (m_curContext) |
| 98 | m_curContext->DecrRef(); |
| 99 | |
| 100 | m_curContext = m_contextList.takeFirst(); |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | |
| 106 | bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt) |
| 107 | { |
| 108 | int64_t pts = pkt->pts; |
| 109 | |
| 110 | if (pts == AV_NOPTS_VALUE) |
| 111 | pts = pkt->dts; |
| 112 | |
| 113 | CheckContext(pts); |
| 114 | |
| 115 | return AvFormatDecoder::ProcessVideoPacket(stream, pkt); |
| 116 | } |
| 117 | |
| 118 | bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
| 119 | DecodeType decodetype) |
| 120 | { |
| 121 | bool ret = true; |
| 122 | |
| 123 | if (curstream->codec->codec_id == AV_CODEC_ID_DVD_NAV) |
| 124 | { |
| 125 | MythDVDContext* context = ringBuffer->DVD()->GetDVDContext(); |
| 126 | |
| 127 | if (context) |
| 128 | m_contextList.append(context); |
| 129 | } |
| 130 | else |
| 131 | { |
| 132 | ret = AvFormatDecoder::ProcessDataPacket(curstream, pkt, decodetype); |
| 133 | } |
| 134 | |
| 135 | return ret; |
| 136 | } |
| 137 | |
77 | 138 | void AvFormatDecoderDVD::PostProcessTracks(void) |
78 | 139 | { |
79 | 140 | if (!ringBuffer) |
… |
… |
void AvFormatDecoderDVD::StreamChangeCheck(void) |
238 | 299 | |
239 | 300 | // Always use the first video stream |
240 | 301 | // (must come after ScanStreams above) |
241 | | selectedTrack[kTrackTypeVideo].av_stream_index = 0; |
| 302 | for (uint i = 0; i < ic->nb_streams; i++) |
| 303 | { |
| 304 | AVStream *st = ic->streams[i]; |
| 305 | if (st && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) |
| 306 | { |
| 307 | selectedTrack[kTrackTypeVideo].av_stream_index = i; |
| 308 | break; |
| 309 | } |
| 310 | } |
242 | 311 | } |
243 | 312 | |
244 | 313 | int AvFormatDecoderDVD::GetAudioLanguage(uint audio_index, uint stream_index) |
diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
index bdb64e4..7a167f0 100644
a
|
b
|
|
1 | 1 | #ifndef AVFORMATDECODERDVD_H |
2 | 2 | #define AVFORMATDECODERDVD_H |
3 | 3 | |
| 4 | #include <QList> |
4 | 5 | #include "avformatdecoder.h" |
5 | 6 | |
| 7 | class MythDVDContext; |
| 8 | |
6 | 9 | class AvFormatDecoderDVD : public AvFormatDecoder |
7 | 10 | { |
8 | 11 | public: |
9 | 12 | AvFormatDecoderDVD(MythPlayer *parent, const ProgramInfo &pginfo, |
10 | 13 | PlayerFlags flags); |
| 14 | virtual ~AvFormatDecoderDVD(); |
11 | 15 | virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file); |
12 | 16 | virtual void UpdateFramesPlayed(void); |
13 | 17 | virtual bool GetFrame(DecodeType decodetype); // DecoderBase |
14 | 18 | |
15 | 19 | protected: |
16 | | int64_t AdjustTimestamp(int64_t timestamp); |
17 | 20 | virtual int ReadPacket(AVFormatContext *ctx, AVPacket *pkt); |
| 21 | virtual bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
| 22 | virtual bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
| 23 | DecodeType decodetype); |
18 | 24 | |
19 | 25 | private: |
20 | 26 | virtual bool DoRewindSeek(long long desiredFrame); |
… |
… |
class AvFormatDecoderDVD : public AvFormatDecoder |
24 | 30 | virtual int GetAudioLanguage(uint audio_index, uint stream_index); |
25 | 31 | virtual AudioTrackType GetAudioTrackType(uint stream_index); |
26 | 32 | |
| 33 | void CheckContext(int64_t pts); |
| 34 | |
27 | 35 | long long DVDFindPosition(long long desiredFrame); |
| 36 | |
| 37 | MythDVDContext* m_curContext; |
| 38 | QList<MythDVDContext*> m_contextList; |
28 | 39 | }; |
29 | 40 | |
30 | 41 | #endif // AVFORMATDECODERDVD_H |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
index 8e2b227..c023d73 100644
a
|
b
|
bool DVDInfo::GetNameAndSerialNum(QString &name, QString &serial) |
78 | 78 | return true; |
79 | 79 | } |
80 | 80 | |
| 81 | MythDVDContext::MythDVDContext() : |
| 82 | ReferenceCounter("MythDVDContext") |
| 83 | { |
| 84 | } |
| 85 | |
| 86 | MythDVDContext::~MythDVDContext() |
| 87 | { |
| 88 | } |
| 89 | |
81 | 90 | DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : |
82 | 91 | RingBuffer(kRingBuffer_DVD), |
83 | 92 | m_dvdnav(NULL), m_dvdBlockReadBuf(NULL), |
… |
… |
DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : |
113 | 122 | m_currentTime(0), |
114 | 123 | m_parent(NULL), |
115 | 124 | m_forcedAspect(-1.0f), |
| 125 | m_contextLock(QMutex::Recursive), m_context(NULL), |
116 | 126 | m_processState(PROCESS_NORMAL), |
117 | 127 | m_dvdStat(DVDNAV_STATUS_OK), |
118 | 128 | m_dvdEvent(0), |
… |
… |
DVDRingBuffer::~DVDRingBuffer() |
149 | 159 | |
150 | 160 | void DVDRingBuffer::CloseDVD(void) |
151 | 161 | { |
| 162 | QMutexLocker contextLocker(&m_contextLock); |
152 | 163 | rwlock.lockForWrite(); |
153 | 164 | if (m_dvdnav) |
154 | 165 | { |
… |
… |
void DVDRingBuffer::CloseDVD(void) |
156 | 167 | dvdnav_close(m_dvdnav); |
157 | 168 | m_dvdnav = NULL; |
158 | 169 | } |
| 170 | |
| 171 | if (m_context) |
| 172 | { |
| 173 | m_context->DecrRef(); |
| 174 | m_context = NULL; |
| 175 | } |
| 176 | |
159 | 177 | m_gotStop = false; |
160 | 178 | m_audioStreamsChanged = true; |
161 | 179 | rwlock.unlock(); |
… |
… |
void DVDRingBuffer::GetDescForPos(QString &desc) |
321 | 339 | |
322 | 340 | bool DVDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) |
323 | 341 | { |
| 342 | QMutexLocker contextLocker(&m_contextLock); |
324 | 343 | rwlock.lockForWrite(); |
325 | 344 | |
326 | 345 | if (m_dvdnav) |
… |
… |
bool DVDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) |
347 | 366 | LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opened DVD device at %1") |
348 | 367 | .arg(fname.constData())); |
349 | 368 | |
| 369 | if (m_context) |
| 370 | m_context->DecrRef(); |
| 371 | |
| 372 | m_context = new MythDVDContext(); |
| 373 | |
350 | 374 | dvdnav_set_readahead_flag(m_dvdnav, 0); |
351 | 375 | dvdnav_set_PGC_positioning_flag(m_dvdnav, 1); |
352 | 376 | |
… |
… |
bool DVDRingBuffer::StartFromBeginning(void) |
408 | 432 | m_endPts = 0; |
409 | 433 | m_timeDiff = 0; |
410 | 434 | |
| 435 | QMutexLocker contextLocker(&m_contextLock); |
| 436 | if (m_context) |
| 437 | m_context->DecrRef(); |
| 438 | |
| 439 | m_context = new MythDVDContext(); |
| 440 | |
411 | 441 | return m_dvdnav; |
412 | 442 | } |
413 | 443 | |
… |
… |
long long DVDRingBuffer::GetReadPosition(void) const |
472 | 502 | return pos * DVD_BLOCK_SIZE; |
473 | 503 | } |
474 | 504 | |
| 505 | uint32_t DVDRingBuffer::AdjustTimestamp(uint32_t timestamp) |
| 506 | { |
| 507 | uint32_t newTimestamp = timestamp; |
| 508 | |
| 509 | if (newTimestamp >= m_timeDiff) |
| 510 | { |
| 511 | newTimestamp -= m_timeDiff; |
| 512 | } |
| 513 | |
| 514 | return newTimestamp; |
| 515 | } |
| 516 | |
| 517 | int64_t DVDRingBuffer::AdjustTimestamp(int64_t timestamp) |
| 518 | { |
| 519 | int64_t newTimestamp = timestamp; |
| 520 | |
| 521 | if (newTimestamp != AV_NOPTS_VALUE && newTimestamp >= m_timeDiff) |
| 522 | { |
| 523 | newTimestamp -= m_timeDiff; |
| 524 | } |
| 525 | |
| 526 | return newTimestamp; |
| 527 | } |
| 528 | |
| 529 | MythDVDContext *DVDRingBuffer::GetDVDContext(void) |
| 530 | { |
| 531 | QMutexLocker contextLocker(&m_contextLock); |
| 532 | |
| 533 | if (m_context) |
| 534 | m_context->IncrRef(); |
| 535 | |
| 536 | return m_context; |
| 537 | } |
| 538 | |
475 | 539 | void DVDRingBuffer::WaitForPlayer(void) |
476 | 540 | { |
477 | 541 | if (!m_skipstillorwait) |
… |
… |
int DVDRingBuffer::safe_read(void *data, uint sz) |
759 | 823 | |
760 | 824 | m_endPts = pci->pci_gi.vobu_e_ptm; |
761 | 825 | |
| 826 | QMutexLocker contextLocker(&m_contextLock); |
| 827 | if (m_context) |
| 828 | m_context->DecrRef(); |
| 829 | |
| 830 | m_context = new MythDVDContext(); |
| 831 | |
| 832 | m_context->m_pci = *pci; |
| 833 | |
| 834 | m_context->m_pci.pci_gi.vobu_s_ptm = AdjustTimestamp(m_context->m_pci.pci_gi.vobu_s_ptm); |
| 835 | m_context->m_pci.pci_gi.vobu_e_ptm = AdjustTimestamp(m_context->m_pci.pci_gi.vobu_e_ptm); |
| 836 | |
| 837 | if (pci->pci_gi.vobu_se_e_ptm != 0) |
| 838 | m_context->m_pci.pci_gi.vobu_se_e_ptm = AdjustTimestamp(m_context->m_pci.pci_gi.vobu_se_e_ptm); |
| 839 | |
762 | 840 | // get the latest nav |
763 | 841 | m_lastNav = (dvdnav_t *)blockBuf; |
764 | 842 | |
765 | | // retrive the latest Data Search Information |
| 843 | // retrieve the latest Data Search Information |
766 | 844 | dsi_t *dsi = dvdnav_get_current_nav_dsi(m_dvdnav); |
767 | 845 | |
| 846 | m_context->m_dsi = *dsi; |
| 847 | |
768 | 848 | // if we are in a looping menu, we don't want to reset the |
769 | 849 | // selected button when we restart |
770 | 850 | m_vobid = dsi->dsi_gi.vobu_vob_idn; |
… |
… |
int DVDRingBuffer::safe_read(void *data, uint sz) |
781 | 861 | |
782 | 862 | if (m_seeking) |
783 | 863 | { |
784 | | |
785 | 864 | int relativetime = |
786 | 865 | (int)((m_seektime - m_currentTime)/ 90000); |
787 | 866 | if (abs(relativetime) <= 1) |
… |
… |
int DVDRingBuffer::safe_read(void *data, uint sz) |
814 | 893 | } |
815 | 894 | |
816 | 895 | // debug |
817 | | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("DVDNAV_NAV_PACKET - time:%1, pos:%2, vob:%3, cell:%4, seeking:%5, seektime:%6") |
818 | | .arg(m_currentTime) |
819 | | .arg(m_currentpos) |
| 896 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6") |
| 897 | .arg(m_context->GetStartPTS()) |
| 898 | .arg(m_context->GetLBA()) |
820 | 899 | .arg(m_vobid) |
821 | 900 | .arg(m_cellid) |
822 | 901 | .arg(m_seeking) |
823 | 902 | .arg(m_seektime)); |
824 | 903 | |
| 904 | if (!m_seeking) |
| 905 | { |
| 906 | memcpy(dest + offset, blockBuf, DVD_BLOCK_SIZE); |
| 907 | tot += DVD_BLOCK_SIZE; |
| 908 | } |
| 909 | |
825 | 910 | // release buffer |
826 | 911 | if (blockBuf != m_dvdBlockWriteBuf) |
827 | 912 | dvdnav_free_cache_block(m_dvdnav, blockBuf); |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h
index 546843b..a331d4a 100644
a
|
b
|
|
12 | 12 | |
13 | 13 | #include "ringbuffer.h" |
14 | 14 | #include "mythdate.h" |
| 15 | #include "referencecounter.h" |
15 | 16 | |
16 | 17 | extern "C" { |
17 | 18 | #include "libavcodec/avcodec.h" |
… |
… |
extern "C" { |
19 | 20 | |
20 | 21 | #include "dvdnav/dvdnav.h" |
21 | 22 | |
| 23 | class MTV_PUBLIC MythDVDContext : public ReferenceCounter |
| 24 | { |
| 25 | friend class DVDRingBuffer; |
| 26 | |
| 27 | public: |
| 28 | virtual ~MythDVDContext(); |
| 29 | |
| 30 | int64_t GetStartPTS() const { return (int64_t)m_pci.pci_gi.vobu_s_ptm; } |
| 31 | int64_t GetEndPTS() const { return (int64_t)m_pci.pci_gi.vobu_e_ptm; } |
| 32 | int64_t GetSeqEndPTS() const { return (int64_t)m_pci.pci_gi.vobu_se_e_ptm; } |
| 33 | uint32_t GetLBA() const { return m_pci.pci_gi.nv_pck_lbn; } |
| 34 | |
| 35 | protected: |
| 36 | MythDVDContext(); |
| 37 | |
| 38 | protected: |
| 39 | dsi_t m_dsi; |
| 40 | pci_t m_pci; |
| 41 | }; |
| 42 | |
22 | 43 | /** \class DVDRingBufferPriv |
23 | 44 | * \brief RingBuffer class for DVD's |
24 | 45 | * |
… |
… |
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
78 | 99 | bool IsWaiting(void) const { return m_dvdWaiting; } |
79 | 100 | int NumPartsInTitle(void) const { return m_titleParts; } |
80 | 101 | void GetMenuSPUPkt(uint8_t *buf, int len, int stream_id, uint32_t startTime); |
81 | | int64_t GetTimeDiff(void) const { return m_timeDiff; } |
| 102 | |
| 103 | uint32_t AdjustTimestamp(uint32_t timestamp); |
| 104 | int64_t AdjustTimestamp(int64_t timestamp); |
| 105 | MythDVDContext* GetDVDContext(void); |
82 | 106 | |
83 | 107 | // Public menu/button stuff |
84 | 108 | AVSubtitle *GetMenuSubtitle(uint &version); |
… |
… |
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
206 | 230 | MythDVDPlayer *m_parent; |
207 | 231 | float m_forcedAspect; |
208 | 232 | |
| 233 | QMutex m_contextLock; |
| 234 | MythDVDContext *m_context; |
209 | 235 | processState_t m_processState; |
210 | 236 | dvdnav_status_t m_dvdStat; |
211 | 237 | int32_t m_dvdEvent; |
diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
index ea08fc9..52cc8e9 100644
a
|
b
|
class AvFormatDecoder : public DecoderBase |
96 | 96 | static void GetDecoders(render_opts &opts); |
97 | 97 | AvFormatDecoder(MythPlayer *parent, const ProgramInfo &pginfo, |
98 | 98 | PlayerFlags flags); |
99 | | ~AvFormatDecoder(); |
| 99 | virtual ~AvFormatDecoder(); |
100 | 100 | |
101 | 101 | virtual void SetEof(bool eof); |
102 | 102 | |
… |
… |
class AvFormatDecoder : public DecoderBase |
222 | 222 | void MpegPreProcessPkt(AVStream *stream, AVPacket *pkt); |
223 | 223 | int H264PreProcessPkt(AVStream *stream, AVPacket *pkt); |
224 | 224 | bool PreProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
225 | | bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
| 225 | virtual bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
226 | 226 | bool ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic); |
227 | 227 | bool ProcessAudioPacket(AVStream *stream, AVPacket *pkt, |
228 | 228 | DecodeType decodetype); |
229 | 229 | bool ProcessSubtitlePacket(AVStream *stream, AVPacket *pkt); |
230 | 230 | bool ProcessRawTextPacket(AVPacket *pkt); |
231 | | bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
232 | | DecodeType decodetype); |
| 231 | virtual bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
| 232 | DecodeType decodetype); |
233 | 233 | |
234 | 234 | void ProcessVBIDataPacket(const AVStream *stream, const AVPacket *pkt); |
235 | 235 | void ProcessDVBDataPacket(const AVStream *stream, const AVPacket *pkt); |