From efbc2941ed4ccc6f033c93426628ec2d2c6a0b35 Mon Sep 17 00:00:00 2001
From: Richard <peper03@yahoo.com>
Date: Sat, 8 Jun 2013 23:37:48 +0200
Subject: [PATCH 4/4] Handle seeking within slideshows.
As slideshows only contain a single video frame to be displayed for an arbitary amount of time along with audio, seeking can cause issues as you may jump over the frame to be displayed.
Using an audio DVD of classical music as an example:
1. Each movement contains a single video frame at the beginning.
2. The second movement has just begun and the user skips back several seconds to the end of the first movement.
3. This change detects that a different video frame should be displayed and jumps back further to retrieve the video frame and, once retrieved, returns to the original position to continue playback.
---
mythtv/libs/libmythdvdnav/dvdnav/searching.c | 4 +-
mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp | 234 ++++++++++++++++------
mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h | 5 +
mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp | 62 +++++-
mythtv/libs/libmythtv/DVD/dvdringbuffer.h | 23 ++-
mythtv/libs/libmythtv/avformatdecoder.h | 2 +-
6 files changed, 261 insertions(+), 69 deletions(-)
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/searching.c b/mythtv/libs/libmythdvdnav/dvdnav/searching.c
index beb2b37..8a6f403 100644
a
|
b
|
dvdnav_status_t dvdnav_relative_time_search(dvdnav_t *this, |
696 | 696 | for (i = 0; i < 19; i++) { |
697 | 697 | if (stime[i]/2.0 <= length/2.0) { |
698 | 698 | offset = dsi->vobu_sri.fwda[i]; |
699 | | if (offset >> 31) { |
| 699 | if (offset != 0x3fffffff) { |
700 | 700 | new_vobu = cur_vobu + (offset & 0xffff); |
701 | 701 | } else { |
702 | 702 | if (cell_nr == last_cell_nr) { |
… |
… |
dvdnav_status_t dvdnav_relative_time_search(dvdnav_t *this, |
715 | 715 | if (stime[18 - i]/2.0 >= abs(length)/2.0) |
716 | 716 | { |
717 | 717 | offset = dsi->vobu_sri.bwda[i]; |
718 | | if (offset >> 31) { |
| 718 | if (offset != 0x3fffffff) { |
719 | 719 | new_vobu = cur_vobu - (offset & 0xffff); |
720 | 720 | } else { |
721 | 721 | if (cell_nr == first_cell_nr) { |
diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
index f4a63c0..d038cfc 100644
a
|
b
|
extern "C" { |
7 | 7 | } |
8 | 8 | |
9 | 9 | #define LOC QString("AFD_DVD: ") |
| 10 | #define INVALID_LBA 0xbfffffff |
10 | 11 | |
11 | 12 | AvFormatDecoderDVD::AvFormatDecoderDVD( |
12 | 13 | MythPlayer *parent, const ProgramInfo &pginfo, PlayerFlags flags) |
13 | 14 | : AvFormatDecoder(parent, pginfo, flags) |
14 | 15 | , m_curContext(NULL) |
15 | 16 | , m_lastVideoPkt(NULL) |
| 17 | , m_lbaLastVideoPkt(INVALID_LBA) |
16 | 18 | , m_framesReq(0) |
| 19 | , m_returnContext(NULL) |
17 | 20 | { |
18 | 21 | } |
19 | 22 | |
20 | 23 | AvFormatDecoderDVD::~AvFormatDecoderDVD() |
21 | 24 | { |
22 | | if (m_curContext) |
23 | | m_curContext->DecrRef(); |
| 25 | ReleaseContext(m_curContext); |
| 26 | ReleaseContext(m_returnContext); |
24 | 27 | |
25 | 28 | while (m_contextList.size() > 0) |
26 | 29 | m_contextList.takeFirst()->DecrRef(); |
27 | 30 | |
| 31 | ReleaseLastVideoPkt(); |
| 32 | } |
| 33 | |
| 34 | void AvFormatDecoderDVD::ReleaseLastVideoPkt() |
| 35 | { |
28 | 36 | if (m_lastVideoPkt) |
29 | 37 | { |
30 | 38 | av_free_packet(m_lastVideoPkt); |
31 | 39 | delete m_lastVideoPkt; |
| 40 | m_lastVideoPkt = NULL; |
| 41 | m_lbaLastVideoPkt = INVALID_LBA; |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | void AvFormatDecoderDVD::ReleaseContext(MythDVDContext *&context) |
| 46 | { |
| 47 | if (context) |
| 48 | { |
| 49 | context->DecrRef(); |
| 50 | context = NULL; |
32 | 51 | } |
33 | 52 | } |
34 | 53 | |
… |
… |
int AvFormatDecoderDVD::ReadPacket(AVFormatContext *ctx, AVPacket* pkt) |
61 | 80 | if (m_framesReq > 0) |
62 | 81 | { |
63 | 82 | m_framesReq--; |
64 | | av_copy_packet(pkt, m_lastVideoPkt); |
65 | 83 | |
66 | | if (m_lastVideoPkt->pts != AV_NOPTS_VALUE) |
67 | | m_lastVideoPkt->pts += pkt->duration; |
| 84 | if (m_lastVideoPkt) |
| 85 | { |
| 86 | av_copy_packet(pkt, m_lastVideoPkt); |
| 87 | |
| 88 | if (m_lastVideoPkt->pts != AV_NOPTS_VALUE) |
| 89 | m_lastVideoPkt->pts += pkt->duration; |
68 | 90 | |
69 | | if (m_lastVideoPkt->dts != AV_NOPTS_VALUE) |
70 | | m_lastVideoPkt->dts += pkt->duration; |
| 91 | if (m_lastVideoPkt->dts != AV_NOPTS_VALUE) |
| 92 | m_lastVideoPkt->dts += pkt->duration; |
| 93 | } |
| 94 | else |
| 95 | { |
| 96 | LOG(VB_GENERAL, LOG_ERR, LOC + QString( "Need to generate frame @ %1 - %2 but no frame available!") |
| 97 | .arg(pkt->pts) |
| 98 | .arg(m_framesReq)); |
| 99 | } |
71 | 100 | } |
72 | 101 | else |
73 | 102 | { |
74 | | result = av_read_frame(ctx, pkt); |
| 103 | bool gotPacket; |
75 | 104 | |
76 | | while (result == AVERROR_EOF && errno == EAGAIN) |
| 105 | do |
77 | 106 | { |
78 | | if (ringBuffer->DVD()->IsReadingBlocked()) |
| 107 | gotPacket = true; |
| 108 | |
| 109 | result = av_read_frame(ctx, pkt); |
| 110 | |
| 111 | while (result == AVERROR_EOF && errno == EAGAIN) |
79 | 112 | { |
80 | | ringBuffer->DVD()->UnblockReading(); |
81 | | result = av_read_frame(ctx, pkt); |
| 113 | if (ringBuffer->DVD()->IsReadingBlocked()) |
| 114 | { |
| 115 | if (ringBuffer->DVD()->GetLastEvent() == DVDNAV_HOP_CHANNEL) |
| 116 | { |
| 117 | // Non-seamless jump - clear all buffers |
| 118 | m_framesReq = 0; |
| 119 | ReleaseContext(m_curContext); |
| 120 | |
| 121 | while (m_contextList.size() > 0) |
| 122 | m_contextList.takeFirst()->DecrRef(); |
| 123 | |
| 124 | Reset(true, false, false); |
| 125 | m_audio->Reset(); |
| 126 | m_parent->DiscardVideoFrames(false); |
| 127 | } |
| 128 | ringBuffer->DVD()->UnblockReading(); |
| 129 | result = av_read_frame(ctx, pkt); |
| 130 | } |
| 131 | else |
| 132 | { |
| 133 | break; |
| 134 | } |
82 | 135 | } |
83 | | else |
| 136 | |
| 137 | if (result >= 0) |
84 | 138 | { |
85 | | break; |
86 | | } |
87 | | } |
| 139 | pkt->dts = ringBuffer->DVD()->AdjustTimestamp(pkt->dts); |
| 140 | pkt->pts = ringBuffer->DVD()->AdjustTimestamp(pkt->pts); |
88 | 141 | |
89 | | if (result >= 0) |
90 | | { |
91 | | pkt->dts = ringBuffer->DVD()->AdjustTimestamp(pkt->dts); |
92 | | pkt->pts = ringBuffer->DVD()->AdjustTimestamp(pkt->pts); |
93 | | } |
| 142 | if (m_returnContext) |
| 143 | { |
| 144 | // We've jumped in a slideshow and have had to jump again |
| 145 | // to find the right video packet to show so only allow |
| 146 | // the packets through that let us find it. |
| 147 | gotPacket = false; |
94 | 148 | |
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 | | } |
| 149 | AVStream *curstream = ic->streams[pkt->stream_index]; |
| 150 | |
| 151 | if ((curstream->codec->codec_type == AVMEDIA_TYPE_VIDEO) || |
| 152 | (curstream->codec->codec_id == AV_CODEC_ID_DVD_NAV)) |
| 153 | { |
| 154 | // Allow video or NAV packets through |
| 155 | gotPacket = true; |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | }while(!gotPacket); |
104 | 160 | } |
105 | 161 | |
106 | 162 | return result; |
… |
… |
void AvFormatDecoderDVD::CheckContext(int64_t pts) |
110 | 166 | { |
111 | 167 | if (pts != AV_NOPTS_VALUE) |
112 | 168 | { |
| 169 | // Remove any contexts we should have |
| 170 | // already processed.(but have somehow jumped past) |
113 | 171 | while (m_contextList.size() > 0 && |
114 | 172 | pts >= m_contextList.first()->GetEndPTS()) |
115 | 173 | { |
116 | | if (m_curContext) |
117 | | m_curContext->DecrRef(); |
118 | | |
| 174 | ReleaseContext(m_curContext); |
119 | 175 | m_curContext = m_contextList.takeFirst(); |
120 | 176 | |
121 | 177 | LOG(VB_GENERAL, LOG_ERR, LOC + |
… |
… |
void AvFormatDecoderDVD::CheckContext(int64_t pts) |
125 | 181 | .arg(m_curContext->GetEndPTS())); |
126 | 182 | } |
127 | 183 | |
| 184 | // See whether we can take the next context from the list |
128 | 185 | if (m_contextList.size() > 0 && |
129 | 186 | pts >= m_contextList.first()->GetStartPTS()) |
130 | 187 | { |
131 | | if (m_curContext) |
132 | | m_curContext->DecrRef(); |
133 | | |
| 188 | ReleaseContext(m_curContext); |
134 | 189 | m_curContext = m_contextList.takeFirst(); |
135 | 190 | |
136 | | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "New DVD context @ %1 - %2") |
137 | | .arg(pts) |
138 | | .arg(m_curContext->GetNumFramesPresent())); |
| 191 | if (m_curContext->GetLBAPrevVideoFrame() != m_lbaLastVideoPkt) |
| 192 | ReleaseLastVideoPkt(); |
139 | 193 | |
140 | 194 | if (m_curContext->GetNumFramesPresent() == 0) |
141 | 195 | { |
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(); |
| 196 | if (m_lastVideoPkt) |
| 197 | { |
| 198 | // No video frames present, so we need to generate |
| 199 | // them based on the last 'sequence end' video packet. |
| 200 | m_framesReq = m_curContext->GetNumFrames(); |
| 201 | } |
| 202 | else |
| 203 | { |
| 204 | // There are no video frames in this VOBU and |
| 205 | // we don't have one stored. We've probably |
| 206 | // jumped into the middle of a cell. |
| 207 | // Jump back to the first VOBU that contains |
| 208 | // video so we can get the video frame we need |
| 209 | // before jumping back again. |
| 210 | m_framesReq = 0; |
| 211 | uint32_t lastVideoSector = m_curContext->GetLBAPrevVideoFrame(); |
| 212 | |
| 213 | if (lastVideoSector != INVALID_LBA) |
| 214 | { |
| 215 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "Missing video. Jumping to sector %1") |
| 216 | .arg(lastVideoSector)); |
| 217 | |
| 218 | ringBuffer->DVD()->SectorSeek(lastVideoSector); |
| 219 | |
| 220 | m_returnContext = m_curContext; |
| 221 | m_curContext = NULL; |
| 222 | } |
| 223 | else |
| 224 | { |
| 225 | LOG(VB_GENERAL, LOG_ERR, LOC + |
| 226 | QString("Missing video frame and no previous frame available! lba: %1") |
| 227 | .arg(m_curContext->GetLBA())); |
| 228 | } |
| 229 | } |
145 | 230 | } |
146 | 231 | else |
147 | 232 | { |
| 233 | // Normal VOBU with at least one video frame so we don't need to generate frames. |
148 | 234 | m_framesReq = 0; |
149 | | if (m_lastVideoPkt) |
150 | | { |
151 | | av_free_packet(m_lastVideoPkt); |
152 | | delete m_lastVideoPkt; |
153 | | m_lastVideoPkt = NULL; |
154 | | } |
| 235 | ReleaseLastVideoPkt(); |
155 | 236 | } |
156 | 237 | } |
157 | 238 | } |
… |
… |
bool AvFormatDecoderDVD::ProcessVideoPacket(AVStream *stream, AVPacket *pkt) |
190 | 271 | |
191 | 272 | av_init_packet(m_lastVideoPkt); |
192 | 273 | av_copy_packet(m_lastVideoPkt, pkt); |
| 274 | m_lbaLastVideoPkt = m_curContext->GetLBA(); |
| 275 | |
| 276 | if (m_returnContext) |
| 277 | { |
| 278 | // After seeking in a slideshow, we needed to find |
| 279 | // the previous video frame to display. |
| 280 | // We've found it now, so we need to jump back to |
| 281 | // where we originally wanted to be. |
| 282 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "Found video packet, jumping back to sector %1") |
| 283 | .arg(m_returnContext->GetLBA())); |
| 284 | |
| 285 | ringBuffer->DVD()->SectorSeek(m_returnContext->GetLBA()); |
| 286 | ReleaseContext(m_returnContext); |
| 287 | } |
| 288 | else |
| 289 | { |
| 290 | if (m_lastVideoPkt->pts != AV_NOPTS_VALUE) |
| 291 | m_lastVideoPkt->pts += pkt->duration; |
| 292 | |
| 293 | if (m_lastVideoPkt->dts != AV_NOPTS_VALUE) |
| 294 | m_lastVideoPkt->dts += pkt->duration; |
| 295 | |
| 296 | m_framesReq = m_curContext->GetNumFrames() - m_curContext->GetNumFramesPresent(); |
193 | 297 | |
194 | | if (m_lastVideoPkt->pts != AV_NOPTS_VALUE) |
195 | | m_lastVideoPkt->pts += pkt->duration; |
| 298 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "SeqEnd @ %1 - require %2 frame(s)") |
| 299 | .arg(pkt->pts) |
| 300 | .arg(m_framesReq)); |
| 301 | } |
| 302 | } |
196 | 303 | |
197 | | if (m_lastVideoPkt->dts != AV_NOPTS_VALUE) |
198 | | m_lastVideoPkt->dts += pkt->duration; |
| 304 | return ret; |
| 305 | } |
199 | 306 | |
200 | | m_framesReq = m_curContext->GetNumFrames() - m_curContext->GetNumFramesPresent(); |
| 307 | bool AvFormatDecoderDVD::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic) |
| 308 | { |
| 309 | bool ret = true; |
201 | 310 | |
202 | | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "SeqEnd @ %1 - require %2 frame(s)") |
203 | | .arg(pkt->pts) |
204 | | .arg(m_framesReq)); |
| 311 | if (m_returnContext == NULL) |
| 312 | { |
| 313 | // Only process video frames if we're not searching for |
| 314 | // the previous video frame after seeking in a slideshow. |
| 315 | ret = AvFormatDecoder::ProcessVideoFrame(stream, mpa_pic); |
205 | 316 | } |
206 | 317 | |
207 | 318 | return ret; |
… |
… |
bool AvFormatDecoderDVD::ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
224 | 335 | // If we don't have a current context, use |
225 | 336 | // the first in the list |
226 | 337 | CheckContext(m_contextList.first()->GetStartPTS()); |
| 338 | |
| 339 | if (m_lastVideoPkt && m_curContext) |
| 340 | { |
| 341 | // If there was no current context but there was |
| 342 | // a video packet, we've almost certainly been |
| 343 | // seeking so set the timestamps of the video |
| 344 | // packet to the new context to ensure we don't |
| 345 | // get sync errors. |
| 346 | m_lastVideoPkt->pts = m_curContext->GetStartPTS(); |
| 347 | m_lastVideoPkt->dts = m_lastVideoPkt->pts; |
| 348 | } |
227 | 349 | } |
228 | 350 | else |
229 | 351 | if (m_lastVideoPkt) |
diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
index 00de975..3d8b548 100644
a
|
b
|
class AvFormatDecoderDVD : public AvFormatDecoder |
19 | 19 | protected: |
20 | 20 | virtual int ReadPacket(AVFormatContext *ctx, AVPacket *pkt); |
21 | 21 | virtual bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
| 22 | virtual bool ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic); |
22 | 23 | virtual bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt, |
23 | 24 | DecodeType decodetype); |
24 | 25 | |
… |
… |
class AvFormatDecoderDVD : public AvFormatDecoder |
31 | 32 | virtual AudioTrackType GetAudioTrackType(uint stream_index); |
32 | 33 | |
33 | 34 | void CheckContext(int64_t pts); |
| 35 | void ReleaseLastVideoPkt(); |
| 36 | void ReleaseContext(MythDVDContext *&context); |
34 | 37 | |
35 | 38 | long long DVDFindPosition(long long desiredFrame); |
36 | 39 | |
37 | 40 | MythDVDContext* m_curContext; |
38 | 41 | QList<MythDVDContext*> m_contextList; |
39 | 42 | AVPacket* m_lastVideoPkt; |
| 43 | uint32_t m_lbaLastVideoPkt; |
40 | 44 | int m_framesReq; |
| 45 | MythDVDContext* m_returnContext; |
41 | 46 | }; |
42 | 47 | |
43 | 48 | #endif // AVFORMATDECODERDVD_H |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
index 2bf1088..cb854d7 100644
a
|
b
|
MythDVDContext::~MythDVDContext() |
87 | 87 | { |
88 | 88 | } |
89 | 89 | |
| 90 | /** \brief Returns the duration of this VOBU in frames |
| 91 | * \sa GetNumFramesPresent |
| 92 | */ |
90 | 93 | int MythDVDContext::GetNumFrames() const |
91 | 94 | { |
92 | 95 | return ((GetEndPTS() - GetStartPTS()) * GetFPS()) / 90000; |
93 | 96 | } |
94 | 97 | |
| 98 | /** \brief Returns the number of video frames present in this VOBU |
| 99 | * \sa GetNumFrames |
| 100 | */ |
95 | 101 | int MythDVDContext::GetNumFramesPresent() const |
96 | 102 | { |
97 | 103 | int frames = 0; |
… |
… |
int MythDVDContext::GetNumFramesPresent() const |
112 | 118 | return frames; |
113 | 119 | } |
114 | 120 | |
| 121 | /** \brief Returns the logical block address of the previous |
| 122 | * VOBU containing video. |
| 123 | * \return LBA or 0xbfffffff if no previous VOBU with video exists |
| 124 | */ |
| 125 | uint32_t MythDVDContext::GetLBAPrevVideoFrame() const |
| 126 | { |
| 127 | uint32_t lba = m_dsi.vobu_sri.prev_video; |
| 128 | |
| 129 | if (lba != 0xbfffffff) |
| 130 | { |
| 131 | // If there is a previous video frame in this |
| 132 | // cell, calculate the absolute LBA from the |
| 133 | // offset |
| 134 | lba = GetLBA() - (lba & 0x7ffffff); |
| 135 | } |
| 136 | |
| 137 | return lba; |
| 138 | } |
| 139 | |
115 | 140 | DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : |
116 | 141 | RingBuffer(kRingBuffer_DVD), |
117 | 142 | m_dvdnav(NULL), m_dvdBlockReadBuf(NULL), |
… |
… |
long long DVDRingBuffer::NormalSeek(long long time) |
295 | 320 | return Seek(time); |
296 | 321 | } |
297 | 322 | |
| 323 | bool DVDRingBuffer::SectorSeek(uint64_t sector) |
| 324 | { |
| 325 | dvdnav_status_t dvdRet = DVDNAV_STATUS_OK; |
| 326 | |
| 327 | QMutexLocker lock(&m_seekLock); |
| 328 | |
| 329 | dvdRet = dvdnav_sector_search(m_dvdnav, sector, SEEK_SET); |
| 330 | |
| 331 | if (dvdRet == DVDNAV_STATUS_ERR) |
| 332 | { |
| 333 | LOG(VB_PLAYBACK, LOG_ERR, LOC + |
| 334 | QString("SectorSeek() to sector %1 failed").arg(sector)); |
| 335 | return false; |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + |
| 340 | QString("DVD Playback SectorSeek() sector: %1").arg(sector)); |
| 341 | return true; |
| 342 | } |
| 343 | } |
| 344 | |
298 | 345 | long long DVDRingBuffer::Seek(long long time) |
299 | 346 | { |
300 | 347 | dvdnav_status_t dvdRet = DVDNAV_STATUS_OK; |
… |
… |
int DVDRingBuffer::safe_read(void *data, uint sz) |
939 | 986 | |
940 | 987 | case DVDNAV_HOP_CHANNEL: |
941 | 988 | { |
942 | | // debug |
943 | | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_HOP_CHANNEL"); |
944 | | WaitForPlayer(); |
| 989 | if (!bReprocessing && !m_skipstillorwait) |
| 990 | { |
| 991 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_HOP_CHANNEL - waiting"); |
| 992 | m_processState = PROCESS_WAIT; |
| 993 | break; |
| 994 | } |
| 995 | else |
| 996 | { |
| 997 | // debug |
| 998 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_HOP_CHANNEL"); |
| 999 | WaitForPlayer(); |
| 1000 | } |
945 | 1001 | } |
946 | 1002 | break; |
947 | 1003 | |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h
index 42e1cfc..c5e4d36 100644
a
|
b
|
extern "C" { |
20 | 20 | |
21 | 21 | #include "dvdnav/dvdnav.h" |
22 | 22 | |
| 23 | /** \class MythDVDContext |
| 24 | * \brief Encapsulates playback context at any given moment. |
| 25 | * |
| 26 | * This class is mainly represents a single VOBU (video object unit) |
| 27 | * on a DVD |
| 28 | */ |
23 | 29 | class MTV_PUBLIC MythDVDContext : public ReferenceCounter |
24 | 30 | { |
25 | 31 | friend class DVDRingBuffer; |
… |
… |
class MTV_PUBLIC MythDVDContext : public ReferenceCounter |
27 | 33 | public: |
28 | 34 | virtual ~MythDVDContext(); |
29 | 35 | |
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 | | int GetNumFrames() const; |
35 | | int GetNumFramesPresent() const; |
36 | | int GetFPS() const { return (m_pci.pci_gi.e_eltm.frame_u & 0x80) ? 30 : 25; } |
| 36 | int64_t GetStartPTS() const { return (int64_t)m_pci.pci_gi.vobu_s_ptm; } |
| 37 | int64_t GetEndPTS() const { return (int64_t)m_pci.pci_gi.vobu_e_ptm; } |
| 38 | int64_t GetSeqEndPTS() const { return (int64_t)m_pci.pci_gi.vobu_se_e_ptm; } |
| 39 | uint32_t GetLBA() const { return m_pci.pci_gi.nv_pck_lbn; } |
| 40 | uint32_t GetLBAPrevVideoFrame() const; |
| 41 | int GetNumFrames() const; |
| 42 | int GetNumFramesPresent() const; |
| 43 | int GetFPS() const { return (m_pci.pci_gi.e_eltm.frame_u & 0x80) ? 30 : 25; } |
37 | 44 | |
38 | 45 | protected: |
39 | 46 | MythDVDContext(); |
… |
… |
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
104 | 111 | uint32_t AdjustTimestamp(uint32_t timestamp); |
105 | 112 | int64_t AdjustTimestamp(int64_t timestamp); |
106 | 113 | MythDVDContext* GetDVDContext(void); |
| 114 | int32_t GetLastEvent(void) const { return m_dvdEvent; } |
107 | 115 | |
108 | 116 | // Public menu/button stuff |
109 | 117 | AVSubtitle *GetMenuSubtitle(uint &version); |
… |
… |
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
143 | 151 | virtual int safe_read(void *data, uint sz); |
144 | 152 | virtual long long Seek(long long pos, int whence, bool has_lock); |
145 | 153 | long long NormalSeek(long long time); |
| 154 | bool SectorSeek(uint64_t sector); |
146 | 155 | void SkipStillFrame(void); |
147 | 156 | void WaitSkip(void); |
148 | 157 | void SkipDVDWaitingForPlayer(void) { m_playerWait = false; } |
diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
index 52cc8e9..04556c5 100644
a
|
b
|
class AvFormatDecoder : public DecoderBase |
223 | 223 | int H264PreProcessPkt(AVStream *stream, AVPacket *pkt); |
224 | 224 | bool PreProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
225 | 225 | virtual bool ProcessVideoPacket(AVStream *stream, AVPacket *pkt); |
226 | | bool ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic); |
| 226 | virtual 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); |