MythTV master
mythcommflagplayer.cpp
Go to the documentation of this file.
1// Qt
2#include <QRunnable>
3
4// MythTV
8
9// Std
10#include <unistd.h>
11#include <iostream>
12
14QWaitCondition MythRebuildSaver::s_wait;
15QHash<DecoderBase*,uint> MythRebuildSaver::s_count;
16
17#define LOC QString("CommFlagPlayer: ")
18
20 : m_decoder(Decoder),
21 m_first(First),
23{
24 QMutexLocker locker(&s_lock);
26}
27
29{
30 m_decoder->SavePositionMapDelta(static_cast<long long>(m_first), static_cast<long long>(m_last));
31
32 QMutexLocker locker(&s_lock);
34 if (!s_count[m_decoder])
35 s_wait.wakeAll();
36}
37
39{
40 QMutexLocker locker(&s_lock);
41 return s_count[Decoder];
42}
43
45{
46 QMutexLocker locker(&s_lock);
47 if (!s_count[Decoder])
48 return;
49
50 while (s_wait.wait(&s_lock))
51 if (!s_count[Decoder])
52 return;
53}
54
56 : MythPlayer(Context, Flags)
57{
58}
59
60bool MythCommFlagPlayer::RebuildSeekTable(bool ShowPercentage, StatusCallback Callback, void* Opaque)
61{
62 uint64_t myFramesPlayed = 0;
63 uint64_t pmap_first = 0;
64 uint64_t pmap_last = 0;
65
66 m_killDecoder = false;
68
69 // clear out any existing seektables
70 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
72 {
77 }
78 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
79
80 if (OpenFile() < 0)
81 return false;
82
83 SetPlaying(true);
84
85 if (!InitVideo())
86 {
87 LOG(VB_GENERAL, LOG_ERR, "RebuildSeekTable unable to initialize video");
88 SetPlaying(false);
89 return false;
90 }
91
93
94 std::chrono::milliseconds save_timeout { 1s + 1ms };
95 MythTimer flagTime;
96 MythTimer ui_timer;
97 MythTimer inuse_timer;
98 MythTimer save_timer;
99 flagTime.start();
100 ui_timer.start();
101 inuse_timer.start();
102 save_timer.start();
103
105
106 if (ShowPercentage)
107 std::cout << "\r \r" << std::flush;
108
109 int prevperc = -1;
110 bool usingIframes = false;
111 while (GetEof() == kEofStateNone)
112 {
113 if (inuse_timer.elapsed() > 2534ms)
114 {
115 inuse_timer.restart();
116 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
119 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
120 }
121
122 if (save_timer.elapsed() > save_timeout)
123 {
124 // Give DB some breathing room if it gets far behind..
125 if (myFramesPlayed - pmap_last > 5000)
126 std::this_thread::sleep_for(200ms);
127
128 // If we're already saving, just save a larger block next time..
130 {
131 pmap_last = myFramesPlayed;
133 new MythRebuildSaver(m_decoder, pmap_first, pmap_last),
134 "RebuildSaver");
135 pmap_first = pmap_last + 1;
136 }
137
138 save_timer.restart();
139 }
140
141 if (ui_timer.elapsed() > 98ms)
142 {
143 ui_timer.restart();
144
145 if (m_totalFrames)
146 {
147 float elapsed = flagTime.elapsed().count() * 0.001F;
148 auto flagFPS = (elapsed > 0.0F) ? static_cast<int>(myFramesPlayed / elapsed) : 0;
149 auto percentage = static_cast<int>(myFramesPlayed * 100 / m_totalFrames);
150 if (Callback)
151 (*Callback)(percentage, Opaque);
152
153 if (ShowPercentage)
154 {
155 QString str = QString("\r%1%/%2fps \r").arg(percentage,3).arg(flagFPS,5);
156 std::cout << qPrintable(str) << std::flush;
157 }
158 else if (percentage % 10 == 0 && prevperc != percentage)
159 {
160 prevperc = percentage;
161 LOG(VB_COMMFLAG, LOG_INFO, QString("Progress %1% @ %2fps").arg(percentage,3).arg(flagFPS,5));
162 }
163 }
164 else
165 {
166 if (ShowPercentage)
167 {
168 QString str = QString("\r%1 \r").arg(myFramesPlayed,6);
169 std::cout << qPrintable(str) << std::flush;
170 }
171 else if (myFramesPlayed % 1000 == 0)
172 {
173 LOG(VB_COMMFLAG, LOG_INFO, QString("Frames processed %1").arg(myFramesPlayed));
174 }
175 }
176 }
177
179 myFramesPlayed = static_cast<uint64_t>(m_decoder->GetFramesRead());
180
181 // H.264 recordings from an HD-PVR contain IDR keyframes,
182 // which are the only valid cut points for lossless cuts.
183 // However, DVB-S h.264 recordings may lack IDR keyframes, in
184 // which case we need to allow non-IDR I-frames. If we get
185 // far enough into the rebuild without having created any
186 // seektable entries, we can assume it is because of the IDR
187 // keyframe setting, and so we rewind and allow h.264 non-IDR
188 // I-frames to be treated as keyframes.
189 auto frames = static_cast<uint64_t>(m_decoder->GetFramesRead());
190 if (!usingIframes &&
191 (GetEof() != kEofStateNone || (frames > 1000 && frames < 1100)) &&
193 {
194 std::cout << "No I-frames found, rewinding..." << std::endl;
196 m_decoder->Reset(true, true, true);
197 pmap_first = pmap_last = myFramesPlayed = 0;
199 usingIframes = true;
200 }
201 }
202
203 if (ShowPercentage)
204 std::cout << "\r \r" << std::flush;
205
208
209 SetPlaying(false);
210 m_killDecoder = true;
211
213 new MythRebuildSaver(m_decoder, pmap_first, myFramesPlayed),
214 "RebuildSaver");
216
217 return true;
218}
219
227{
228 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
231 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
232
233 if (!m_decoderThread)
234 DecoderStart(false);
235
236 if (FrameNumber >= 0)
237 {
238 DoJumpToFrame(static_cast<uint64_t>(FrameNumber), kInaccuracyNone);
240 }
241
242 int tries = 0;
243 while (!m_videoOutput->ValidVideoFrames() && ((tries++) < 100))
244 {
245 m_decodeOneFrame = true;
246 std::this_thread::sleep_for(10ms);
247 if ((tries & 10) == 10)
248 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms for video frame");
249 }
250
253}
254
virtual void SetIdrOnlyKeyframes(bool)
Definition: decoderbase.h:160
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
Definition: decoderbase.cpp:47
bool HasPositionMap(void) const
Definition: decoderbase.h:218
long long GetFramesRead(void) const
Definition: decoderbase.h:194
void TrackTotalDuration(bool track)
Definition: decoderbase.h:251
uint64_t SavePositionMapDelta(long long first_frame, long long last_frame)
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
static MThreadPool * globalInstance(void)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
bool RebuildSeekTable(bool ShowPercentage=true, StatusCallback Callback=nullptr, void *Opaque=nullptr)
MythVideoFrame * GetRawVideoFrame(long long FrameNumber=-1)
Returns a specific frame from the video.
MythCommFlagPlayer(PlayerContext *Context, PlayerFlags Flags=kNoFlags)
void SaveTotalDuration(void)
bool m_decodeOneFrame
Definition: mythplayer.h:389
MythDecoderThread * m_decoderThread
Definition: mythplayer.h:367
virtual void DecoderStart(bool start_paused)
DecoderBase * m_decoder
Definition: mythplayer.h:362
static const double kInaccuracyNone
Definition: mythplayer.h:239
void DoJumpToFrame(uint64_t frame, double inaccuracy)
uint64_t m_framesPlayed
Definition: mythplayer.h:424
virtual int OpenFile(int Retries=4)
Definition: mythplayer.cpp:417
uint64_t m_totalFrames
Definition: mythplayer.h:425
bool DecoderGetFrame(DecodeType decodetype, bool unsafe=false)
bool volatile m_killDecoder
Definition: mythplayer.h:388
void SaveTotalFrames(void)
void ClearAfterSeek(bool clearvideobuffers=true)
This is to support seeking...
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:242
PlayerContext * m_playerCtx
Definition: mythplayer.h:366
MythVideoOutput * m_videoOutput
Definition: mythplayer.h:364
EofState GetEof(void) const
virtual bool InitVideo(void)
Definition: mythplayer.cpp:270
static QWaitCondition s_wait
static QHash< DecoderBase *, uint > s_count
static uint GetCount(DecoderBase *Decoder)
void run() override
static QMutex s_lock
static void Wait(DecoderBase *Decoder)
DecoderBase * m_decoder
MythRebuildSaver(DecoderBase *Decoder, uint64_t First, uint64_t Last)
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
std::chrono::milliseconds restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
Definition: mythtimer.cpp:62
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
virtual void StartDisplayingFrame()
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
virtual int ValidVideoFrames() const
Returns number of frames that are fully decoded.
virtual MythVideoFrame * GetLastShownFrame()
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
void LockPlayingInfo(const char *file, int line) const
void UnlockPlayingInfo(const char *file, int line) const
ProgramInfo * m_playingInfo
Currently playing info.
void UpdateInUseMark(bool force=false)
void ClearPositionMap(MarkTypes type) const
@ kEofStateNone
Definition: decoderbase.h:69
@ kDecodeNothing
Definition: decoderbase.h:49
unsigned int uint
Definition: freesurround.h:24
#define LOC
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
PlayerFlags
Definition: mythplayer.h:65
void(*)(int, void *) StatusCallback
Definition: mythplayer.h:51
@ MARK_KEYFRAME
Definition: programtypes.h:61
@ MARK_GOP_BYFRAME
Definition: programtypes.h:63
@ MARK_DURATION_MS
Definition: programtypes.h:73
@ MARK_GOP_START
Definition: programtypes.h:60
struct exc__state * m_last
Definition: pxsup2dast.c:93