MythTV master
mythdvddecoder.cpp
Go to the documentation of this file.
1// MythTV
4
5#include "mythdvdbuffer.h"
6#include "mythdvdplayer.h"
7#include "mythdvddecoder.h"
8
9// FFmpeg
10extern "C" {
11#include "libavcodec/avcodec.h"
12}
13
14// Std
15#include <thread>
16
17#define LOC QString("DVDDec: ")
18
20 : AvFormatDecoder(Parent, PGInfo, Flags)
21{
22}
23
25{
28
29 while (!m_contextList.empty())
30 m_contextList.takeFirst()->DecrRef();
31
33}
34
36{
38 {
39 av_packet_free(&m_lastVideoPkt);
41 }
42}
43
45{
46 if (Context)
47 {
48 Context->DecrRef();
49 Context = nullptr;
50 }
51}
52
53void MythDVDDecoder::Reset(bool ResetVideoData, bool SeekReset, bool ResetFile)
54{
55 AvFormatDecoder::Reset(ResetVideoData, SeekReset, ResetFile);
57}
58
59
61{
62 if (!m_ringBuffer->IsDVD())
63 return;
64
65 auto currentpos = static_cast<long long>(m_ringBuffer->DVD()->GetCurrentTime().count() * m_fps);
66 m_framesPlayed = m_framesRead = currentpos ;
67 m_parent->SetFramesPlayed(static_cast<uint64_t>(currentpos + 1));
68}
69
70bool MythDVDDecoder::GetFrame(DecodeType /*Type*/, bool &Retry)
71{
72 // Always try to decode audio and video for DVDs
74}
75
76int MythDVDDecoder::ReadPacket(AVFormatContext *Ctx, AVPacket* Pkt, bool& StorePacket)
77{
78 int result = 0;
79
80 if (m_framesReq > 0)
81 {
83
85 {
86 av_packet_ref(Pkt, m_lastVideoPkt);
87 if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
88 m_lastVideoPkt->pts += Pkt->duration;
89 if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
90 m_lastVideoPkt->dts += Pkt->duration;
91 }
92 else
93 {
94 LOG(VB_GENERAL, LOG_ERR, LOC + QString( "Need to generate frame @ %1 - %2 but no frame available!")
95 .arg(Pkt->pts).arg(m_framesReq));
96 }
97 }
98 else
99 {
100 bool gotPacket = false;
101
102 while (!gotPacket)
103 {
104 gotPacket = true;
105
106 m_avCodecLock.lock();
107 result = av_read_frame(Ctx, Pkt);
108 m_avCodecLock.unlock();
109 std::this_thread::yield();
110
111 while (m_ringBuffer->DVD()->IsReadingBlocked())
112 {
113 int32_t lastEvent = m_ringBuffer->DVD()->GetLastEvent();
114 switch(lastEvent)
115 {
116 case DVDNAV_HOP_CHANNEL:
117 // Non-seamless jump - clear all buffers
118 m_framesReq = 0;
120 while (!m_contextList.empty())
121 m_contextList.takeFirst()->DecrRef();
122 Reset(true, false, false);
123 m_audio->Reset();
124 m_parent->DiscardVideoFrames(false, false);
125 // During a seek, the Reset call above resets the frames played
126 // to zero - so we need to re-establish our position. Playback
127 // appears unaffected by removing the Reset call - but better
128 // safe than sorry when it comes to DVD so just update
129 // the frames played.
131 break;
132
133 case DVDNAV_WAIT:
134 case DVDNAV_STILL_FRAME:
135 if (m_storedPackets.count() > 0)
136 {
137 // Ringbuffer is waiting for the player
138 // to empty its buffers but we have one or
139 // more frames in our buffer that have not
140 // yet been sent to the player.
141 // Make sure no more frames will be buffered
142 // for the time being and start emptying our
143 // buffer.
144
145 // Force AvFormatDecoder to stop buffering frames
146 StorePacket = false;
147 // Return the first buffered packet
148 AVPacket *storedPkt = m_storedPackets.takeFirst();
149 av_packet_ref(Pkt, storedPkt);
150 av_packet_unref(storedPkt);
151 delete storedPkt;
152 return 0;
153 }
154 break;
155
156 case DVDNAV_NAV_PACKET:
157 // Don't need to do anything here. There was a timecode discontinuity
158 // and the ringbuffer returned to make sure that any packets still in
159 // ffmpeg's buffers were flushed.
160 break;
161 default:
162 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unexpected DVD event - %1")
163 .arg(lastEvent));
164 break;
165 }
166
168
169 m_avCodecLock.lock();
170 result = av_read_frame(Ctx, Pkt);
171 m_avCodecLock.unlock();
172
173 // Make sure we yield. Otherwise other threads may not
174 // get chance to take the lock. Shouldn't be necessary
175 // but calling up the OSD menu in a still frame without
176 // this still causes a deadlock.
177 std::this_thread::yield();
178 }
179
180 if (result >= 0)
181 {
182 Pkt->dts = m_ringBuffer->DVD()->AdjustTimestamp(Pkt->dts);
183 Pkt->pts = m_ringBuffer->DVD()->AdjustTimestamp(Pkt->pts);
184
185 if (m_returnContext)
186 {
187 // We've jumped in a slideshow and have had to jump again
188 // to find the right video packet to show so only allow
189 // the packets through that let us find it.
190 gotPacket = false;
191
192 AVStream *curstream = m_ic->streams[Pkt->stream_index];
193
194 if ((curstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||
195 (curstream->codecpar->codec_id == AV_CODEC_ID_DVD_NAV))
196 {
197 // Allow video or NAV packets through
198 gotPacket = true;
199 }
200 }
201 }
202 }
203 }
204
205 return result;
206}
207
209{
210 if (Pts != AV_NOPTS_VALUE)
211 {
212 // Remove any contexts we should have
213 // already processed.(but have somehow jumped past)
214 while (!m_contextList.empty() && (Pts >= m_contextList.first()->GetEndPTS()))
215 {
217 m_curContext = m_contextList.takeFirst();
218 LOG(VB_GENERAL, LOG_ERR, LOC + QString("DVD context missed! lba: %1, curpts: %2, nav end pts: %3")
219 .arg(m_curContext->GetLBA()).arg(Pts).arg(m_curContext->GetEndPTS()));
220 }
221
222 // See whether we can take the next context from the list
223 if (!m_contextList.empty() && (Pts >= m_contextList.first()->GetStartPTS()))
224 {
226 m_curContext = m_contextList.takeFirst();
227
230
232 {
233 if (m_lastVideoPkt)
234 {
235 // No video frames present, so we need to generate
236 // them based on the last 'sequence end' video packet.
238 }
239 else
240 {
241 // There are no video frames in this VOBU and
242 // we don't have one stored. We've probably
243 // jumped into the middle of a cell.
244 // Jump back to the first VOBU that contains
245 // video so we can get the video frame we need
246 // before jumping back again.
247 m_framesReq = 0;
248 uint32_t lastVideoSector = m_curContext->GetLBAPrevVideoFrame();
249
250 if (lastVideoSector != INVALID_LBA)
251 {
252 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Missing video. Jumping to sector %1")
253 .arg(lastVideoSector));
254 m_ringBuffer->DVD()->SectorSeek(lastVideoSector);
256 m_curContext = nullptr;
257 }
258 else
259 {
260 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Missing video frame and no previous frame available! lba: %1")
261 .arg(m_curContext->GetLBA()));
262 }
263 }
264 }
265 else
266 {
267 // Normal VOBU with at least one video frame so we don't need to generate frames.
268 m_framesReq = 0;
270 }
271 }
272 }
273}
274
275
276bool MythDVDDecoder::ProcessVideoPacket(AVCodecContext* codecContext, AVStream *Stream, AVPacket *Pkt, bool &Retry)
277{
278 int64_t pts = Pkt->pts;
279
280 if (pts == AV_NOPTS_VALUE)
281 pts = Pkt->dts;
282
284
285 bool ret = AvFormatDecoder::ProcessVideoPacket(codecContext, Stream, Pkt, Retry);
286 if (Retry)
287 return ret;
288
289 if (ret && m_curContext && (pts != AV_NOPTS_VALUE) && (pts + Pkt->duration == m_curContext->GetSeqEndPTS()))
290 {
291 // If this video frame is the last in the sequence,
292 // make a copy of it so we can 'generate' more
293 // to fill in the gaps (e.g. when a single frame
294 // should be displayed with audio)
295 if (!m_lastVideoPkt)
296 {
297 // This packet will be freed in the destructor.
298 m_lastVideoPkt = av_packet_alloc();
299 }
300 else
301 {
302 av_packet_unref(m_lastVideoPkt);
303 }
304 av_packet_ref(m_lastVideoPkt, Pkt);
306
307 if (m_returnContext)
308 {
309 // After seeking in a slideshow, we needed to find
310 // the previous video frame to display.
311 // We've found it now, so we need to jump back to
312 // where we originally wanted to be.
313 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "Found video packet, jumping back to sector %1")
314 .arg(m_returnContext->GetLBA()));
315
318 }
319 else
320 {
321 if (m_lastVideoPkt->pts != AV_NOPTS_VALUE)
322 m_lastVideoPkt->pts += Pkt->duration;
323
324 if (m_lastVideoPkt->dts != AV_NOPTS_VALUE)
325 m_lastVideoPkt->dts += Pkt->duration;
326
328
329 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString( "SeqEnd @ %1 - require %2 frame(s)")
330 .arg(Pkt->pts).arg(m_framesReq));
331 }
332 }
333
334 return ret;
335}
336
337bool MythDVDDecoder::ProcessVideoFrame(AVCodecContext* codecContext, AVStream *Stream, AVFrame *Frame)
338{
339 bool ret = true;
340
341 if (m_returnContext == nullptr)
342 {
343 // Only process video frames if we're not searching for
344 // the previous video frame after seeking in a slideshow.
345 ret = AvFormatDecoder::ProcessVideoFrame(codecContext, Stream, Frame);
346 }
347
348 return ret;
349}
350
351bool MythDVDDecoder::ProcessDataPacket(AVStream *Curstream, AVPacket *Pkt,
352 DecodeType Decodetype)
353{
354 bool ret = true;
355
356 if (Curstream->codecpar->codec_id == AV_CODEC_ID_DVD_NAV)
357 {
359
360 if (context)
361 m_contextList.append(context);
362
363 if ((m_curContext == nullptr) && (!m_contextList.empty()))
364 {
365 // If we don't have a current context, use
366 // the first in the list
367 CheckContext(m_contextList.first()->GetStartPTS());
368
370 {
371 // If there was no current context but there was
372 // a video packet, we've almost certainly been
373 // seeking so set the timestamps of the video
374 // packet to the new context to ensure we don't
375 // get sync errors.
377 m_lastVideoPkt->dts = m_lastVideoPkt->pts;
378 }
379 }
380 else if (m_lastVideoPkt)
381 {
382 // If we've been generating frames, see whether this
383 // new context should be used already (handles
384 // situations where a VOBU consists of only a NAV
385 // packet and nothing else)
387 }
388 }
389 else
390 {
391 ret = AvFormatDecoder::ProcessDataPacket(Curstream, Pkt, Decodetype);
392 }
393
394 return ret;
395}
396
398{
399 if (!m_ringBuffer)
400 return;
401 if (!m_ringBuffer->IsDVD())
402 return;
403
404 QMutexLocker locker(&m_trackLock);
405
406 if (m_tracks[kTrackTypeAudio].size() > 1)
407 {
408 stable_sort(m_tracks[kTrackTypeAudio].begin(), m_tracks[kTrackTypeAudio].end());
409
410 int trackNo = -1;
411 int dvdTrack = m_ringBuffer->DVD()->GetTrack(kTrackTypeAudio);
412
413 for (uint i = 0; i < m_tracks[kTrackTypeAudio].size(); i++)
414 {
415 LOG(VB_PLAYBACK, LOG_INFO, LOC +
416 QString("DVD Audio Track Map Stream id #%1, av_stream_idx %2, MPEG stream 0x%3, lang %4")
417 .arg(m_tracks[kTrackTypeAudio][i].m_stream_id)
418 .arg(m_tracks[kTrackTypeAudio][i].m_av_stream_index)
419 .arg(m_ic->streams[m_tracks[kTrackTypeAudio][i].m_av_stream_index]->id,0,16)
420 .arg(iso639_key_toName(m_tracks[kTrackTypeAudio][i].m_language)));
421
422 // Find the audio track in our list that maps to the
423 // selected track in the ringbuffer (the ringbuffer's
424 // list should be in the same order but can have gaps,
425 // so we look for the track with the same index)
426 if (m_tracks[kTrackTypeAudio][i].m_stream_id == dvdTrack)
427 trackNo = static_cast<int>(i);
428 }
429
430 if (trackNo < 0 && (!m_tracks[kTrackTypeAudio].empty()))
431 {
432 // Take the first track
433 trackNo = 0;
434 }
435
436 if (trackNo >= 0)
437 SetTrack(kTrackTypeAudio, trackNo);
438 }
439
440 if (!m_tracks[kTrackTypeSubtitle].empty())
441 {
442 std::map<int,uint> lang_sub_cnt;
443 std::map<int,int> stream2idx;
444
445 // First, create a map containing stream id -> track index
446 // of the subtitle streams that have been found so far.
447 for (uint n = 0; n < m_tracks[kTrackTypeSubtitle].size(); n++)
448 {
449 int stream_id = m_tracks[kTrackTypeSubtitle][n].m_stream_id & 0x1f;
450 stream2idx[stream_id] = static_cast<int>(n);
451 }
452
453 // Get all subtitle tracks from the DVD and filter out any that
454 // are not mapped in the current program chain.
455 sinfo_vec_t filteredTracks;
456
457 if (!m_ringBuffer->DVD()->IsInMenu())
458 {
459 filteredTracks.reserve(32);
460 for (uint i = 0; i < 32; ++i)
461 {
462 int8_t streamid = m_ringBuffer->DVD()->GetSubtitleTrackNum(i);
463 if (streamid >= 0)
464 {
465 // This stream is mapped in the current program chain
466 int lang = static_cast<int>(m_ringBuffer->DVD()->GetSubtitleLanguage(static_cast<int>(i)));
467 uint lang_indx = lang_sub_cnt[lang]++;
468 int trackNo = -1;
469
470 if (stream2idx.contains(streamid))
471 trackNo = stream2idx[streamid];
472
473 if (trackNo == -1)
474 {
475 // Create a dummy track if the physical stream has not
476 // yet been seen.
477 filteredTracks.emplace_back(-1, streamid, lang, lang_indx);
478 }
479 else
480 {
481 // Otherwise use the real data
482 filteredTracks.push_back(m_tracks[kTrackTypeSubtitle][static_cast<uint>(trackNo)]);
483 filteredTracks.back().m_stream_id &= 0x1f;
484 filteredTracks.back().m_language = lang;
485 filteredTracks.back().m_language_index = lang_indx;
486 }
487 }
488 }
489 }
490
491 m_tracks[kTrackTypeSubtitle] = filteredTracks;
492 stable_sort(m_tracks[kTrackTypeSubtitle].begin(), m_tracks[kTrackTypeSubtitle].end());
493
494 int track = -1;
495 int selectedStream = m_ringBuffer->DVD()->GetTrack(kTrackTypeSubtitle);
496
497 // Now iterate over the sorted list and try to find the index of the
498 // currently selected track.
499 for (uint idx = 0; idx < m_tracks[kTrackTypeSubtitle].size(); idx++)
500 {
501 const StreamInfo& stream = m_tracks[kTrackTypeSubtitle][idx];
502 int avidx = stream.m_av_stream_index;
503 QString mpegstream;
504
505 if (avidx >= 0)
506 mpegstream = QString( "0x%1").arg(m_ic->streams[avidx]->id,0,16);
507 else
508 mpegstream = "n/a";
509
510 LOG(VB_PLAYBACK, LOG_INFO, LOC +
511 QString("DVD Subtitle Track Map Stream id #%1, av_stream_idx %2, MPEG #%3, lang %4")
512 .arg(stream.m_stream_id)
513 .arg(stream.m_av_stream_index)
514 .arg(mpegstream,
515 iso639_key_toName(stream. m_language)));
516
517 if ((selectedStream != -1) && (stream.m_stream_id == selectedStream))
518 track = static_cast<int>(idx);
519 }
520
521 int trackcount = static_cast<int>(m_tracks[kTrackTypeSubtitle].size());
522 if (auto * dvdplayer = qobject_cast<MythDVDPlayer*>(m_parent); dvdplayer && (track < 0 || track >= trackcount))
523 {
524 emit dvdplayer->DisableDVDSubtitles();
525 }
526 else if (track >= 0 && track < trackcount)
527 {
529 if (auto * player = qobject_cast<MythPlayerUI*>(m_parent); player)
530 emit player->EnableSubtitles(true);
531 }
532 }
533}
534
535bool MythDVDDecoder::DoRewindSeek(long long DesiredFrame)
536{
537 if (!m_ringBuffer->IsDVD())
538 return false;
539
540 m_ringBuffer->Seek(DVDFindPosition(DesiredFrame), SEEK_SET);
541 m_framesPlayed = m_framesRead = m_lastKey = DesiredFrame + 1;
542 m_frameCounter += 100;
543 return true;
544}
545
546void MythDVDDecoder::DoFastForwardSeek(long long DesiredFrame, bool &NeedFlush)
547{
548 if (!m_ringBuffer->IsDVD())
549 return;
550
551 m_ringBuffer->Seek(DVDFindPosition(DesiredFrame), SEEK_SET);
552 NeedFlush = true;
553 m_framesPlayed = m_framesRead = m_lastKey = DesiredFrame + 1;
554 m_frameCounter += 100;
555}
556
558{
559 if (!m_ringBuffer->IsDVD())
560 return;
561
563 {
564 // This was originally in HandleDVDStreamChange
565 m_trackLock.lock();
566 ScanStreams(true);
567 m_trackLock.unlock();
568 m_streamsChanged=false;
569 }
570
571 // Update the title length
573 {
574 ResetPosMap();
577 }
578
579 // rescan the non-video streams as necessary
581 ScanStreams(true);
582
583 // Always use the first video stream
584 // (must come after ScanStreams above)
585 for (uint i = 0; i < m_ic->nb_streams; i++)
586 {
587 AVStream *st = m_ic->streams[i];
588 if (st && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
589 {
590 m_trackLock.lock();
591 m_selectedTrack[kTrackTypeVideo].m_av_stream_index = static_cast<int>(i);
592 m_trackLock.unlock();
593 break;
594 }
595 }
596}
597
598int MythDVDDecoder::GetAudioLanguage(uint /*AudioIndex*/, uint StreamIndex)
599{
600 if ((m_ic->streams[StreamIndex]->id >= 0) && (m_ringBuffer && m_ringBuffer->IsDVD()))
601 {
602 auto track = m_ringBuffer->DVD()->GetAudioTrackNum(static_cast<uint>(m_ic->streams[StreamIndex]->id));
603 return static_cast<int>(m_ringBuffer->DVD()->GetAudioLanguage(track));
604 }
605 return iso639_str3_to_key("und");
606}
607
608long long MythDVDDecoder::DVDFindPosition(long long DesiredFrame)
609{
610 if (!m_ringBuffer->IsDVD())
611 return 0;
612
613 int ffrewSkip = 1;
614 int current_speed = 0;
615 if (m_parent)
616 {
617 ffrewSkip = m_parent->GetFFRewSkip();
618 current_speed = static_cast<int>(m_parent->GetNextPlaySpeed());
619 }
620
621 if (ffrewSkip == 1 || ffrewSkip == 0)
622 {
623 std::chrono::seconds diffTime = std::chrono::seconds(static_cast<int>(ceil((DesiredFrame - m_framesPlayed) / m_fps)));
624 std::chrono::seconds desiredTimePos = m_ringBuffer->DVD()->GetCurrentTime() +
625 diffTime;
626 if (diffTime <= 0s)
627 desiredTimePos--;
628 else
629 desiredTimePos++;
630
631 if (desiredTimePos < 0s)
632 desiredTimePos = 0s;
633 return (desiredTimePos.count() * 90000LL);
634 }
635 return current_speed;
636}
637
639{
640 int type = 0;
641
642 if (m_ringBuffer && m_ringBuffer->DVD())
643 {
644 int logical_idx = m_ringBuffer->DVD()->GetAudioTrackNum(static_cast<uint>(m_ic->streams[Index]->id));
645 type = m_ringBuffer->DVD()->GetAudioTrackType(static_cast<uint>(logical_idx));
646 }
647
648 // These are the only types defined in unofficial documentation
649 if (type > 0 && type < 5)
650 {
652 switch (type)
653 {
654 case 1: return kAudioTypeNormal;
655 case 2: return kAudioTypeAudioDescription;
656 case 3:
657 case 4: return kAudioTypeCommentary;
658 default: break;
659 }
660 return ret;
661 }
662
663 // If the DVD metadata doesn't include the info then we might as well fall through, maybe we'll get lucky
665}
AVFrame AVFrame
void Reset(void)
Definition: audioplayer.cpp:92
A decoder for media files.
AVFormatContext * m_ic
void Reset(bool reset_video_data, bool seek_reset, bool reset_file) override
bool GetFrame(DecodeType Type, bool &Retry) override
Demux, preprocess and possibly decode a frame of video/audio.
int ScanStreams(bool novideo)
int SetTrack(uint Type, int TrackNo) override
QList< AVPacket * > m_storedPackets
void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames) override
virtual AudioTrackType GetAudioTrackType(uint StreamIndex)
virtual bool ProcessDataPacket(AVStream *curstream, AVPacket *pkt, DecodeType decodetype)
QRecursiveMutex m_avCodecLock
virtual bool ProcessVideoFrame(AVCodecContext *codecContext, AVStream *Stream, AVFrame *AvFrame)
virtual bool ProcessVideoPacket(AVCodecContext *codecContext, AVStream *stream, AVPacket *pkt, bool &Retry)
uint64_t m_frameCounter
Definition: decoderbase.h:292
double m_fps
Definition: decoderbase.h:282
long long m_framesRead
Definition: decoderbase.h:291
MythMediaBuffer * m_ringBuffer
Definition: decoderbase.h:280
QRecursiveMutex m_trackLock
Definition: decoderbase.h:337
virtual void ResetPosMap(void)
MythPlayer * m_parent
Definition: decoderbase.h:277
std::array< sinfo_vec_t, kTrackTypeCount > m_tracks
Definition: decoderbase.h:340
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
long long m_lastKey
Definition: decoderbase.h:295
AudioPlayer * m_audio
Definition: decoderbase.h:279
long long m_framesPlayed
Definition: decoderbase.h:290
std::array< StreamInfo, kTrackTypeCount > m_selectedTrack
Definition: decoderbase.h:342
int GetAudioTrackNum(uint StreamId)
get the logical track index (into PGC_AST_CTL) of the element that maps the given physical stream id.
uint GetSubtitleLanguage(int Id)
Get the subtitle language from the dvd.
int GetTrack(uint Type) const
get the track the dvd should be playing.
int32_t GetLastEvent(void) const
bool SectorSeek(uint64_t Sector)
uint32_t AdjustTimestamp(uint32_t Timestamp) const
uint GetAudioLanguage(int Index)
get the audio language from the dvd
int8_t GetSubtitleTrackNum(uint StreamId)
get the logical subtitle track/stream number from the dvd
std::chrono::seconds GetCurrentTime(void) const
bool PGCLengthChanged(void)
check if pgc length has changed
bool AudioStreamsChanged(void) const
int GetAudioTrackType(uint Index)
MythDVDContext * GetDVDContext(void)
void UnblockReading(void)
bool IsReadingBlocked(void)
Encapsulates playback context at any given moment.
int GetNumFramesPresent(void) const
Returns the number of video frames present in this VOBU.
int64_t GetEndPTS(void) const
uint32_t GetLBA(void) const
uint32_t GetLBAPrevVideoFrame(void) const
Returns the logical block address of the previous VOBU containing video.
int64_t GetSeqEndPTS(void) const
int GetNumFrames(void) const
Returns the duration of this VOBU in frames.
int64_t GetStartPTS(void) const
uint32_t m_lbaLastVideoPkt
void CheckContext(int64_t Pts)
bool GetFrame(DecodeType Type, bool &Retry) override
Demux, preprocess and possibly decode a frame of video/audio.
~MythDVDDecoder() override
MythDVDContext * m_returnContext
long long DVDFindPosition(long long DesiredFrame)
int GetAudioLanguage(uint AudioIndex, uint StreamIndex) override
bool ProcessVideoFrame(AVCodecContext *codecContext, AVStream *Stream, AVFrame *Frame) override
QList< MythDVDContext * > m_contextList
MythDVDDecoder(MythPlayer *Parent, const ProgramInfo &PGInfo, PlayerFlags Flags)
bool DoRewindSeek(long long DesiredFrame) override
bool ProcessDataPacket(AVStream *Curstream, AVPacket *Pkt, DecodeType Decodetype) override
int ReadPacket(AVFormatContext *Ctx, AVPacket *Pkt, bool &StorePacket) override
MythDVDContext * m_curContext
void PostProcessTracks(void) override
void Reset(bool ResetVideoData, bool SeekReset, bool ResetFile) override
void UpdateFramesPlayed(void) override
void StreamChangeCheck(void) override
static void ReleaseContext(MythDVDContext *&Context)
AudioTrackType GetAudioTrackType(uint Index) override
void DoFastForwardSeek(long long DesiredFrame, bool &NeedFlush) override
Seeks to the keyframe just before the desiredFrame if exact seeks is enabled, or the frame just after...
AVPacket * m_lastVideoPkt
bool ProcessVideoPacket(AVCodecContext *codecContext, AVStream *Stream, AVPacket *Pkt, bool &Retry) override
void ReleaseLastVideoPkt(void)
bool IsDVD(void) const
long long Seek(long long Position, int Whence, bool HasLock=false)
const MythDVDBuffer * DVD(void) const
bool IsInMenu(void) const override
float GetNextPlaySpeed(void) const
Definition: mythplayer.h:139
void SetFramesPlayed(uint64_t played)
Definition: mythplayer.cpp:556
bool AtNormalSpeed(void) const
Definition: mythplayer.h:156
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:642
int GetFFRewSkip(void) const
Definition: mythplayer.h:136
Holds information on recordings and videos.
Definition: programinfo.h:75
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
int m_av_stream_index
Definition: decoderbase.h:103
int m_stream_id
Definition: decoderbase.h:104
unsigned int uint
Definition: compat.h:60
AudioTrackType
Definition: decoderbase.h:56
@ kAudioTypeCommentary
Definition: decoderbase.h:62
@ kAudioTypeAudioDescription
Definition: decoderbase.h:58
@ kAudioTypeNormal
Definition: decoderbase.h:57
std::vector< StreamInfo > sinfo_vec_t
Definition: decoderbase.h:118
@ kTrackTypeSubtitle
Definition: decoderbase.h:31
@ kTrackTypeAudio
Definition: decoderbase.h:29
@ kTrackTypeVideo
Definition: decoderbase.h:30
DecodeType
Definition: decoderbase.h:48
@ kDecodeAV
Definition: decoderbase.h:52
QString iso639_key_toName(int iso639_2)
Converts a canonical key to language name in English.
Definition: iso639.cpp:114
ISO 639-1 and ISO 639-2 support functions.
static int iso639_str3_to_key(const unsigned char *iso639_2)
Definition: iso639.h:60
#define LOC
static constexpr uint32_t INVALID_LBA
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
PlayerFlags
Definition: mythplayer.h:64
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
Definition: mythchrono.h:45