PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 7ms app.codeStats 1ms

/mythtv/libs/libmythtv/mythplayer.cpp

http://github.com/MythTV/mythtv
C++ | 5631 lines | 4474 code | 724 blank | 433 comment | 1168 complexity | 7110c5f81af804cb5d2fabab6ecf7a6f MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MIT, GPL-2.0, LGPL-2.0, BSD-3-Clause, GPL-3.0, LGPL-2.1, LGPL-3.0, MPL-2.0-no-copyleft-exception
  1. // -*- Mode: c++ -*-
  2. #undef HAVE_AV_CONFIG_H
  3. // C++ headers
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <cmath> // for fabs, ceil, round, signbit
  7. #include <cstdint>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <unistd.h>
  11. using namespace std;
  12. // Qt headers
  13. #include <QCoreApplication>
  14. #include <QDir>
  15. #include <QHash> // for QHash
  16. #include <QMap> // for QMap<>::iterator, etc
  17. #include <QThread> // for QThread, etc
  18. #include <QtCore/qnumeric.h> // for qIsNaN
  19. #include <utility>
  20. // MythTV headers
  21. #include "mthread.h"
  22. #include "mythconfig.h"
  23. #include "mythplayer.h"
  24. #include "DetectLetterbox.h"
  25. #include "audioplayer.h"
  26. #include "interactivescreen.h"
  27. #include "programinfo.h"
  28. #include "mythcorecontext.h"
  29. #include "livetvchain.h"
  30. #include "decoderbase.h"
  31. #include "nuppeldecoder.h"
  32. #include "avformatdecoder.h"
  33. #include "dummydecoder.h"
  34. #include "tv_play.h"
  35. #include "interactivetv.h"
  36. #include "mythsystemevent.h"
  37. #include "mythlogging.h"
  38. #include "mythmiscutil.h"
  39. #include "io/mythinteractivebuffer.h"
  40. #include "audiooutput.h"
  41. #include "cardutil.h"
  42. #include "mythavutil.h"
  43. #include "jitterometer.h"
  44. #include "mythtimer.h"
  45. #include "mythuiactions.h"
  46. #include "io/mythmediabuffer.h"
  47. #include "tv_actions.h"
  48. #include "mythcodeccontext.h"
  49. // MythUI headers
  50. #include <mythmainwindow.h>
  51. extern "C" {
  52. #include "libavcodec/avcodec.h"
  53. }
  54. #include "remoteencoder.h"
  55. #if ! HAVE_ROUND
  56. #define round(x) ((int) ((x) + 0.5))
  57. #endif
  58. static unsigned dbg_ident(const MythPlayer* /*player*/);
  59. #define LOC QString("Player(%1): ").arg(dbg_ident(this),0,36)
  60. #define LOC_DEC QString("Player(%1): ").arg(dbg_ident(m_mp),0,36)
  61. const int MythPlayer::kNightModeBrightenssAdjustment = 10;
  62. const int MythPlayer::kNightModeContrastAdjustment = 10;
  63. // Exact frame seeking, no inaccuracy allowed.
  64. const double MythPlayer::kInaccuracyNone = 0;
  65. // By default, when seeking, snap to a keyframe if the keyframe's
  66. // distance from the target frame is less than 10% of the total seek
  67. // distance.
  68. const double MythPlayer::kInaccuracyDefault = 0.1;
  69. // Allow greater inaccuracy (50%) in the cutlist editor (unless the
  70. // editor seek distance is set to 1 frame or 1 keyframe).
  71. const double MythPlayer::kInaccuracyEditor = 0.5;
  72. // Any negative value means completely inexact, i.e. seek to the
  73. // keyframe that is closest to the target.
  74. const double MythPlayer::kInaccuracyFull = -1.0;
  75. void DecoderThread::run(void)
  76. {
  77. RunProlog();
  78. LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread starting.");
  79. if (m_mp)
  80. m_mp->DecoderLoop(m_startPaused);
  81. LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread exiting.");
  82. RunEpilog();
  83. }
  84. static int toCaptionType(int type)
  85. {
  86. if (kTrackTypeCC608 == type) return kDisplayCC608;
  87. if (kTrackTypeCC708 == type) return kDisplayCC708;
  88. if (kTrackTypeSubtitle == type) return kDisplayAVSubtitle;
  89. if (kTrackTypeTeletextCaptions == type) return kDisplayTeletextCaptions;
  90. if (kTrackTypeTextSubtitle == type) return kDisplayTextSubtitle;
  91. if (kTrackTypeRawText == type) return kDisplayRawTextSubtitle;
  92. return 0;
  93. }
  94. static int toTrackType(int type)
  95. {
  96. if (kDisplayCC608 == type) return kTrackTypeCC608;
  97. if (kDisplayCC708 == type) return kTrackTypeCC708;
  98. if (kDisplayAVSubtitle == type) return kTrackTypeSubtitle;
  99. if (kDisplayTeletextCaptions == type) return kTrackTypeTeletextCaptions;
  100. if (kDisplayTextSubtitle == type) return kTrackTypeTextSubtitle;
  101. if (kDisplayRawTextSubtitle == type) return kTrackTypeRawText;
  102. return kTrackTypeUnknown;
  103. }
  104. MythMultiLocker::MythMultiLocker(std::initializer_list<QMutex*> Locks)
  105. : m_locks(Locks)
  106. {
  107. Relock();
  108. }
  109. MythMultiLocker::~MythMultiLocker()
  110. {
  111. Unlock();
  112. }
  113. void MythMultiLocker::Unlock(void)
  114. {
  115. for (QVector<QMutex*>::const_reverse_iterator it = m_locks.crbegin(); it != m_locks.crend(); ++it)
  116. if (*it)
  117. (*it)->unlock();
  118. }
  119. void MythMultiLocker::Relock(void)
  120. {
  121. foreach (auto lock, m_locks)
  122. if (lock)
  123. lock->lock();
  124. }
  125. MythPlayer::MythPlayer(PlayerFlags flags)
  126. : m_playerFlags(flags),
  127. m_display((flags & kVideoIsNull) ? nullptr : MythDisplay::AcquireRelease()),
  128. // CC608/708
  129. m_cc608(this), m_cc708(this),
  130. // Audio
  131. m_audio(this, (flags & kAudioMuted) != 0),
  132. // Debugging variables
  133. m_outputJmeter(new Jitterometer(LOC))
  134. {
  135. m_playerThread = QThread::currentThread();
  136. #ifdef Q_OS_ANDROID
  137. m_playerThreadId = gettid();
  138. #endif
  139. // Playback (output) zoom control
  140. m_detectLetterBox = new DetectLetterbox(this);
  141. m_vbiMode = VBIMode::Parse(gCoreContext->GetSetting("VbiFormat"));
  142. m_captionsEnabledbyDefault = gCoreContext->GetBoolSetting("DefaultCCMode");
  143. m_itvEnabled = gCoreContext->GetBoolSetting("EnableMHEG", false);
  144. m_clearSavedPosition = gCoreContext->GetNumSetting("ClearSavedPosition", 1);
  145. m_endExitPrompt = gCoreContext->GetNumSetting("EndOfRecordingExitPrompt");
  146. m_pipDefaultLoc = (PIPLocation)gCoreContext->GetNumSetting("PIPLocation", kPIPTopLeft);
  147. // Get VBI page number
  148. QString mypage = gCoreContext->GetSetting("VBIpageNr", "888");
  149. bool valid = false;
  150. uint tmp = mypage.toInt(&valid, 16);
  151. m_ttPageNum = (valid) ? tmp : m_ttPageNum;
  152. m_cc608.SetTTPageNum(m_ttPageNum);
  153. m_avTimer.start();
  154. }
  155. MythPlayer::~MythPlayer(void)
  156. {
  157. // NB the interactiveTV thread is a client of OSD so must be deleted
  158. // before locking and deleting the OSD
  159. {
  160. QMutexLocker lk0(&m_itvLock);
  161. delete m_interactiveTV;
  162. m_interactiveTV = nullptr;
  163. }
  164. MythMultiLocker locker({&m_osdLock, &m_vidExitLock});
  165. delete m_osd;
  166. m_osd = nullptr;
  167. SetDecoder(nullptr);
  168. delete m_decoderThread;
  169. m_decoderThread = nullptr;
  170. delete m_videoOutput;
  171. m_videoOutput = nullptr;
  172. delete m_outputJmeter;
  173. m_outputJmeter = nullptr;
  174. delete m_detectLetterBox;
  175. m_detectLetterBox = nullptr;
  176. if (m_display)
  177. MythDisplay::AcquireRelease(false);
  178. }
  179. void MythPlayer::SetWatchingRecording(bool mode)
  180. {
  181. m_watchingRecording = mode;
  182. if (m_decoder)
  183. m_decoder->SetWatchingRecording(mode);
  184. }
  185. bool MythPlayer::IsWatchingInprogress(void) const
  186. {
  187. return m_watchingRecording && m_playerCtx->m_recorder &&
  188. m_playerCtx->m_recorder->IsValidRecorder();
  189. }
  190. void MythPlayer::PauseBuffer(void)
  191. {
  192. m_bufferPauseLock.lock();
  193. if (m_playerCtx->m_buffer)
  194. {
  195. m_playerCtx->m_buffer->Pause();
  196. m_playerCtx->m_buffer->WaitForPause();
  197. }
  198. m_bufferPaused = true;
  199. m_bufferPauseLock.unlock();
  200. }
  201. void MythPlayer::UnpauseBuffer(void)
  202. {
  203. m_bufferPauseLock.lock();
  204. if (m_playerCtx->m_buffer)
  205. m_playerCtx->m_buffer->Unpause();
  206. m_bufferPaused = false;
  207. m_bufferPauseLock.unlock();
  208. }
  209. bool MythPlayer::Pause(void)
  210. {
  211. while (!m_pauseLock.tryLock(100))
  212. {
  213. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms to get pause lock.");
  214. DecoderPauseCheck();
  215. }
  216. bool already_paused = m_allPaused;
  217. if (already_paused)
  218. {
  219. m_pauseLock.unlock();
  220. return already_paused;
  221. }
  222. m_nextPlaySpeed = 0.0;
  223. m_nextNormalSpeed = false;
  224. PauseVideo();
  225. m_audio.Pause(true);
  226. PauseDecoder();
  227. PauseBuffer();
  228. if (!m_decoderPaused)
  229. PauseDecoder(); // Retry in case audio only stream
  230. m_allPaused = m_decoderPaused && m_videoPaused && m_bufferPaused;
  231. {
  232. if (FlagIsSet(kVideoIsNull) && m_decoder)
  233. m_decoder->UpdateFramesPlayed();
  234. else if (m_videoOutput && !FlagIsSet(kVideoIsNull))
  235. m_framesPlayed = m_videoOutput->GetFramesPlayed();
  236. }
  237. m_pauseLock.unlock();
  238. return already_paused;
  239. }
  240. bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
  241. {
  242. m_pauseLock.lock();
  243. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  244. QString("Play(%1, normal %2, unpause audio %3)")
  245. .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
  246. if (m_deleteMap.IsEditing())
  247. {
  248. LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
  249. m_pauseLock.unlock();
  250. return false;
  251. }
  252. m_rtcBase = 0;
  253. m_priorAudioTimecode = 0;
  254. m_priorVideoTimecode = 0;
  255. m_lastFix = 0.0;
  256. SetEof(kEofStateNone);
  257. UnpauseBuffer();
  258. UnpauseDecoder();
  259. if (unpauseaudio)
  260. m_audio.Pause(false);
  261. UnpauseVideo();
  262. m_allPaused = false;
  263. m_nextPlaySpeed = speed;
  264. m_nextNormalSpeed = normal;
  265. m_pauseLock.unlock();
  266. return true;
  267. }
  268. void MythPlayer::PauseVideo(void)
  269. {
  270. m_videoPauseLock.lock();
  271. m_needNewPauseFrame = true;
  272. m_videoPaused = true;
  273. m_videoPauseLock.unlock();
  274. }
  275. void MythPlayer::UnpauseVideo(void)
  276. {
  277. m_videoPauseLock.lock();
  278. m_videoPaused = false;
  279. m_videoPauseLock.unlock();
  280. }
  281. void MythPlayer::SetPlayingInfo(const ProgramInfo &pginfo)
  282. {
  283. assert(m_playerCtx);
  284. if (!m_playerCtx)
  285. return;
  286. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  287. m_playerCtx->SetPlayingInfo(&pginfo);
  288. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  289. }
  290. void MythPlayer::SetPlaying(bool is_playing)
  291. {
  292. QMutexLocker locker(&m_playingLock);
  293. m_playing = is_playing;
  294. m_playingWaitCond.wakeAll();
  295. }
  296. bool MythPlayer::IsPlaying(uint wait_in_msec, bool wait_for) const
  297. {
  298. QMutexLocker locker(&m_playingLock);
  299. if (!wait_in_msec)
  300. return m_playing;
  301. MythTimer t;
  302. t.start();
  303. while ((wait_for != m_playing) && ((uint)t.elapsed() < wait_in_msec))
  304. {
  305. m_playingWaitCond.wait(
  306. &m_playingLock, max(0,(int)wait_in_msec - t.elapsed()));
  307. }
  308. return m_playing;
  309. }
  310. bool MythPlayer::InitVideo(void)
  311. {
  312. if (!m_playerCtx)
  313. return false;
  314. PIPState pipState = m_playerCtx->GetPIPState();
  315. if (!m_decoder)
  316. {
  317. LOG(VB_GENERAL, LOG_ERR, LOC +
  318. "Cannot create a video renderer without a decoder.");
  319. return false;
  320. }
  321. m_videoOutput = MythVideoOutput::Create(
  322. m_decoder->GetCodecDecoderName(),
  323. m_decoder->GetVideoCodecID(),
  324. pipState, m_videoDim, m_videoDispDim, m_videoAspect,
  325. m_parentWidget, m_embedRect,
  326. m_videoFrameRate, (uint)m_playerFlags, m_codecName, m_maxReferenceFrames);
  327. if (!m_videoOutput)
  328. {
  329. LOG(VB_GENERAL, LOG_ERR, LOC +
  330. "Couldn't create VideoOutput instance. Exiting..");
  331. SetErrored(tr("Failed to initialize video output"));
  332. return false;
  333. }
  334. if (m_embedding && pipState == kPIPOff)
  335. m_videoOutput->EmbedInWidget(m_embedRect);
  336. return true;
  337. }
  338. void MythPlayer::ReinitOSD(void)
  339. {
  340. if (m_videoOutput && !FlagIsSet(kVideoIsNull))
  341. {
  342. m_osdLock.lock();
  343. if (!is_current_thread(m_playerThread))
  344. {
  345. m_reinitOsd = true;
  346. m_osdLock.unlock();
  347. return;
  348. }
  349. QRect visible;
  350. QRect total;
  351. float aspect = NAN;
  352. float scaling = NAN;
  353. m_videoOutput->GetOSDBounds(total, visible, aspect,
  354. scaling, 1.0F);
  355. if (m_osd)
  356. {
  357. m_osd->SetPainter(m_videoOutput->GetOSDPainter());
  358. int stretch = lroundf(aspect * 100);
  359. if ((m_osd->Bounds() != visible) ||
  360. (m_osd->GetFontStretch() != stretch))
  361. {
  362. uint old = m_textDisplayMode;
  363. ToggleCaptions(old);
  364. m_osd->Reinit(visible, aspect);
  365. EnableCaptions(old, false);
  366. if (m_deleteMap.IsEditing())
  367. {
  368. bool const changed = m_deleteMap.IsChanged();
  369. m_deleteMap.SetChanged(true);
  370. m_deleteMap.UpdateOSD(m_framesPlayed, m_videoFrameRate, m_osd);
  371. m_deleteMap.SetChanged(changed);
  372. }
  373. }
  374. }
  375. #ifdef USING_MHEG
  376. if (GetInteractiveTV())
  377. {
  378. QMutexLocker locker(&m_itvLock);
  379. m_interactiveTV->Reinit(total, visible, aspect);
  380. m_itvVisible = false;
  381. }
  382. #endif // USING_MHEG
  383. m_reinitOsd = false;
  384. m_osdLock.unlock();
  385. }
  386. }
  387. void MythPlayer::ReinitVideo(bool ForceUpdate)
  388. {
  389. bool aspect_only = false;
  390. {
  391. MythMultiLocker locker({&m_osdLock, &m_vidExitLock});
  392. m_videoOutput->SetVideoFrameRate(static_cast<float>(m_videoFrameRate));
  393. float aspect = (m_forcedVideoAspect > 0) ? m_forcedVideoAspect : m_videoAspect;
  394. if (!m_videoOutput->InputChanged(m_videoDim, m_videoDispDim, aspect,
  395. m_decoder->GetVideoCodecID(), aspect_only, &locker,
  396. m_maxReferenceFrames, ForceUpdate))
  397. {
  398. LOG(VB_GENERAL, LOG_ERR, LOC +
  399. "Failed to Reinitialize Video. Exiting..");
  400. SetErrored(tr("Failed to reinitialize video output"));
  401. return;
  402. }
  403. if (m_osd)
  404. m_osd->SetPainter(m_videoOutput->GetOSDPainter());
  405. ReinitOSD();
  406. }
  407. if (!aspect_only)
  408. ClearAfterSeek();
  409. if (m_textDisplayMode)
  410. EnableSubtitles(true);
  411. AutoVisualise();
  412. }
  413. static inline QString toQString(FrameScanType scan) {
  414. switch (scan) {
  415. case kScan_Ignore: return QString("Ignore Scan");
  416. case kScan_Detect: return QString("Detect Scan");
  417. case kScan_Interlaced: return QString("Interlaced Scan");
  418. case kScan_Progressive: return QString("Progressive Scan");
  419. default: return QString("Unknown Scan");
  420. }
  421. }
  422. FrameScanType MythPlayer::detectInterlace(FrameScanType newScan,
  423. FrameScanType scan,
  424. float fps, int video_height) const
  425. {
  426. QString dbg = QString("detectInterlace(") + toQString(newScan) +
  427. QString(", ") + toQString(scan) + QString(", ") +
  428. QString("%1").arg(static_cast<double>(fps)) + QString(", ") +
  429. QString("%1").arg(video_height) + QString(") ->");
  430. if (kScan_Ignore != newScan || kScan_Detect == scan)
  431. {
  432. // The scanning mode should be decoded from the stream, but if it
  433. // isn't, we have to guess.
  434. scan = kScan_Interlaced; // default to interlaced
  435. if ((720 == video_height) || // ATSC 720p
  436. (fps > 45)) // software deinterlacing
  437. scan = kScan_Progressive;
  438. if (kScan_Detect != newScan)
  439. scan = newScan;
  440. };
  441. LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg +toQString(scan));
  442. return scan;
  443. }
  444. void MythPlayer::SetKeyframeDistance(int keyframedistance)
  445. {
  446. m_keyframeDist = (keyframedistance > 0) ? static_cast<uint>(keyframedistance) : m_keyframeDist;
  447. }
  448. /*! \brief Check whether deinterlacing should be enabled
  449. *
  450. * If the user has triggered an override, this will always be used (until 'detect'
  451. * is requested to turn it off again).
  452. *
  453. * For H264 material, the decoder will signal when the current frame is on a new
  454. * GOP boundary and if the frame's interlaced flag does not match the current
  455. * scan type, the scan type is unlocked. This works well for all test clips
  456. * with mixed progressive/interlaced sequences.
  457. *
  458. * For all other material, we lock the scan type to interlaced when interlaced
  459. * frames are seen - and do not unlock if we see progressive frames. This is
  460. * primarily targetted at MPEG2 material where there is a lot of content where
  461. * the scan type changes frequently - and for no obvious reason. This will result
  462. * in 'false positives' in some cases but there is no clear approach that works
  463. * for all cases. The previous behaviour is preserved (i.e. lock to interlaced
  464. * if interlaced frames are seen) which results in less erratic playback (as the
  465. * deinterlacers are not continually switched on and off) and correctly deinterlaces
  466. * material that is not otherwise flagged correctly.
  467. */
  468. void MythPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
  469. {
  470. if (!frame)
  471. return;
  472. if ((m_scanOverride > kScan_Detect) && (m_scan != m_scanOverride))
  473. {
  474. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Locking scan override to '%1'")
  475. .arg(ScanTypeToString(m_scanOverride, true)));
  476. SetScanType(m_scanOverride);
  477. }
  478. // This is currently only signalled for H264 content
  479. if (frame->new_gop)
  480. {
  481. if (m_scanOverride < kScan_Interlaced &&
  482. ((frame->interlaced_frame && !is_interlaced(m_scan)) ||
  483. (!frame->interlaced_frame && is_interlaced(m_scan))))
  484. {
  485. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Unlocking frame scan");
  486. m_scanLocked = false;
  487. }
  488. }
  489. if (m_scanLocked)
  490. return;
  491. if (frame->interlaced_frame)
  492. {
  493. if (m_scanTracker < 0)
  494. {
  495. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  496. QString("Interlaced frame seen after %1 progressive frames")
  497. .arg(abs(m_scanTracker)));
  498. m_scanTracker = 2;
  499. if (allow_lock)
  500. {
  501. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Locking scan to Interlaced.");
  502. SetScanType(kScan_Interlaced);
  503. return;
  504. }
  505. }
  506. m_scanTracker++;
  507. }
  508. else
  509. {
  510. if (m_scanTracker > 0)
  511. {
  512. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  513. QString("Progressive frame seen after %1 interlaced frames")
  514. .arg(m_scanTracker));
  515. m_scanTracker = 0;
  516. }
  517. m_scanTracker--;
  518. }
  519. int min_count = !allow_lock ? 0 : 2;
  520. if (abs(m_scanTracker) <= min_count)
  521. return;
  522. SetScanType((m_scanTracker > min_count) ? kScan_Interlaced : kScan_Progressive);
  523. m_scanLocked = false;
  524. }
  525. FrameScanType MythPlayer::NextScanOverride(void)
  526. {
  527. int next = m_scanOverride + 1;
  528. if (next > kScan_Progressive)
  529. next = kScan_Detect;
  530. return static_cast<FrameScanType>(next);
  531. }
  532. void MythPlayer::SetScanOverride(FrameScanType Scan)
  533. {
  534. if (m_scanOverride == Scan)
  535. return;
  536. m_scanOverride = Scan;
  537. if (m_scanOverride == kScan_Detect)
  538. {
  539. m_scanLocked = false;
  540. m_scanInitialized = false;
  541. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Reverting to auto detection of scan");
  542. }
  543. }
  544. FrameScanType MythPlayer::GetScanType(void) const
  545. {
  546. if (m_scanOverride > kScan_Detect)
  547. return m_scanOverride;
  548. return m_scan;
  549. }
  550. void MythPlayer::SetScanType(FrameScanType Scan)
  551. {
  552. if (!is_current_thread(m_playerThread))
  553. {
  554. m_resetScan = Scan;
  555. return;
  556. }
  557. if (!m_videoOutput)
  558. return;
  559. m_resetScan = kScan_Ignore;
  560. if (m_scanInitialized && m_scan == Scan && m_frameIntervalPrev == m_frameInterval)
  561. return;
  562. m_scanLocked = (Scan != kScan_Detect);
  563. m_scanInitialized = true;
  564. m_frameIntervalPrev = m_frameInterval;
  565. if (is_interlaced(Scan))
  566. {
  567. MythDeintType forced = m_playerCtx->IsPiPOrSecondaryPBP() ? (DEINT_CPU | DEINT_MEDIUM) : DEINT_NONE;
  568. bool normal = m_playSpeed > 0.99F && m_playSpeed < 1.01F && m_normalSpeed;
  569. m_doubleFramerate = CanSupportDoubleRate() && normal && !forced;
  570. m_videoOutput->SetDeinterlacing(true, m_doubleFramerate, forced);
  571. }
  572. else if (kScan_Progressive == Scan)
  573. {
  574. m_doubleFramerate = false;
  575. m_videoOutput->SetDeinterlacing(false, false);
  576. }
  577. m_scan = Scan;
  578. }
  579. void MythPlayer::SetVideoParams(int width, int height, double fps,
  580. float aspect, bool ForceUpdate,
  581. int ReferenceFrames, FrameScanType scan, const QString& codecName)
  582. {
  583. bool paramsChanged = ForceUpdate;
  584. if (width >= 0 && height >= 0)
  585. {
  586. paramsChanged = true;
  587. m_videoDim = m_videoDispDim = QSize(width, height);
  588. m_videoAspect = aspect > 0.0F ? aspect : static_cast<float>(width) / height;
  589. }
  590. if (!qIsNaN(fps) && fps > 0.0 && fps < 121.0)
  591. {
  592. paramsChanged = true;
  593. m_videoFrameRate = fps;
  594. if (m_ffrewSkip != 0 && m_ffrewSkip != 1)
  595. {
  596. UpdateFFRewSkip();
  597. }
  598. else
  599. {
  600. float temp_speed = (m_playSpeed == 0.0F) ?
  601. m_audio.GetStretchFactor() : m_playSpeed;
  602. SetFrameInterval(kScan_Progressive,
  603. 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
  604. }
  605. }
  606. if (!codecName.isEmpty())
  607. {
  608. m_codecName = codecName;
  609. paramsChanged = true;
  610. }
  611. if (ReferenceFrames > 0)
  612. {
  613. m_maxReferenceFrames = ReferenceFrames;
  614. paramsChanged = true;
  615. }
  616. if (!paramsChanged)
  617. return;
  618. if (m_videoOutput)
  619. ReinitVideo(ForceUpdate);
  620. if (IsErrored())
  621. return;
  622. // ensure deinterlacers are correctly reset after a change
  623. m_scanInitialized = false;
  624. SetScanType(detectInterlace(scan, m_scan, static_cast<float>(m_videoFrameRate),
  625. m_videoDispDim.height()));
  626. m_scanLocked = false;
  627. m_scanTracker = (m_scan == kScan_Interlaced) ? 2 : 0;
  628. }
  629. void MythPlayer::SetFrameRate(double fps)
  630. {
  631. m_videoFrameRate = fps;
  632. float temp_speed = (m_playSpeed == 0.0F) ?
  633. m_audio.GetStretchFactor() : m_playSpeed;
  634. SetFrameInterval(kScan_Progressive,
  635. 1.0 / (m_videoFrameRate * static_cast<double>(temp_speed)));
  636. }
  637. void MythPlayer::SetFileLength(int total, int frames)
  638. {
  639. m_totalLength = total;
  640. m_totalFrames = frames;
  641. }
  642. void MythPlayer::SetDuration(int duration)
  643. {
  644. m_totalDuration = duration;
  645. }
  646. void MythPlayer::OpenDummy(void)
  647. {
  648. m_isDummy = true;
  649. if (!m_videoOutput)
  650. {
  651. SetKeyframeDistance(15);
  652. SetVideoParams(720, 576, 25.00, 1.25F, false, 2);
  653. }
  654. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  655. auto *dec = new DummyDecoder(this, *(m_playerCtx->m_playingInfo));
  656. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  657. SetDecoder(dec);
  658. }
  659. void MythPlayer::CreateDecoder(char *TestBuffer, int TestSize)
  660. {
  661. if (AvFormatDecoder::CanHandle(TestBuffer, m_playerCtx->m_buffer->GetFilename(), TestSize))
  662. {
  663. SetDecoder(new AvFormatDecoder(this, *m_playerCtx->m_playingInfo, m_playerFlags));
  664. return;
  665. }
  666. if (NuppelDecoder::CanHandle(TestBuffer, TestSize))
  667. SetDecoder(new NuppelDecoder(this, *m_playerCtx->m_playingInfo));
  668. }
  669. int MythPlayer::OpenFile(int Retries)
  670. {
  671. // Sanity check
  672. if (!m_playerCtx || (m_playerCtx && !m_playerCtx->m_buffer))
  673. return -1;
  674. LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opening '%1'")
  675. .arg(m_playerCtx->m_buffer->GetSafeFilename()));
  676. // Disable hardware acceleration for second PBP
  677. if (m_playerCtx && (m_playerCtx->IsPBP() && !m_playerCtx->IsPrimaryPBP()) &&
  678. FlagIsSet(kDecodeAllowGPU))
  679. {
  680. m_playerFlags = static_cast<PlayerFlags>(m_playerFlags - kDecodeAllowGPU);
  681. }
  682. m_isDummy = false;
  683. m_liveTV = m_playerCtx->m_tvchain && m_playerCtx->m_buffer->LiveMode();
  684. // Dummy setup for livetv transtions. Can we get rid of this?
  685. if (m_playerCtx->m_tvchain)
  686. {
  687. int currentposition = m_playerCtx->m_tvchain->GetCurPos();
  688. if (m_playerCtx->m_tvchain->GetInputType(currentposition) == "DUMMY")
  689. {
  690. OpenDummy();
  691. return 0;
  692. }
  693. }
  694. // Start the RingBuffer read ahead thread
  695. m_playerCtx->m_buffer->Start();
  696. /// OSX has a small stack, so we put this buffer on the heap instead.
  697. char *testbuf = new char[kDecoderProbeBufferSize];
  698. UnpauseBuffer();
  699. // delete any pre-existing recorder
  700. SetDecoder(nullptr);
  701. int testreadsize = 2048;
  702. // Test the incoming buffer and create a suitable decoder
  703. MythTimer bigTimer;
  704. bigTimer.start();
  705. int timeout = max((Retries + 1) * 500, 30000);
  706. while (testreadsize <= kDecoderProbeBufferSize)
  707. {
  708. MythTimer peekTimer;
  709. peekTimer.start();
  710. while (m_playerCtx->m_buffer->Peek(testbuf, testreadsize) != testreadsize)
  711. {
  712. // NB need to allow for streams encountering network congestion
  713. if (peekTimer.elapsed() > 30000 || bigTimer.elapsed() > timeout
  714. || m_playerCtx->m_buffer->GetStopReads())
  715. {
  716. LOG(VB_GENERAL, LOG_ERR, LOC +
  717. QString("OpenFile(): Could not read first %1 bytes of '%2'")
  718. .arg(testreadsize)
  719. .arg(m_playerCtx->m_buffer->GetFilename()));
  720. delete[] testbuf;
  721. SetErrored(tr("Could not read first %1 bytes").arg(testreadsize));
  722. return -1;
  723. }
  724. LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
  725. usleep(50 * 1000);
  726. }
  727. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  728. CreateDecoder(testbuf, testreadsize);
  729. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  730. if (m_decoder || (bigTimer.elapsed() > timeout))
  731. break;
  732. testreadsize <<= 1;
  733. }
  734. // Fail
  735. if (!m_decoder)
  736. {
  737. LOG(VB_GENERAL, LOG_ERR, LOC +
  738. QString("Couldn't find an A/V decoder for: '%1'")
  739. .arg(m_playerCtx->m_buffer->GetFilename()));
  740. SetErrored(tr("Could not find an A/V decoder"));
  741. delete[] testbuf;
  742. return -1;
  743. }
  744. if (m_decoder->IsErrored())
  745. {
  746. LOG(VB_GENERAL, LOG_ERR, LOC + "Could not initialize A/V decoder.");
  747. SetDecoder(nullptr);
  748. SetErrored(tr("Could not initialize A/V decoder"));
  749. delete[] testbuf;
  750. return -1;
  751. }
  752. // Pre-init the decoder
  753. m_decoder->SetSeekSnap(0);
  754. m_decoder->SetLiveTVMode(m_liveTV);
  755. m_decoder->SetWatchingRecording(m_watchingRecording);
  756. m_decoder->SetTranscoding(m_transcoding);
  757. // Open the decoder
  758. int result = m_decoder->OpenFile(m_playerCtx->m_buffer, false, testbuf, testreadsize);
  759. delete[] testbuf;
  760. if (result < 0)
  761. {
  762. LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open decoder for: %1")
  763. .arg(m_playerCtx->m_buffer->GetFilename()));
  764. SetErrored(tr("Could not open decoder"));
  765. return -1;
  766. }
  767. // Disable audio if necessary
  768. m_audio.CheckFormat();
  769. // Livetv, recording or in-progress
  770. if (result > 0)
  771. {
  772. m_hasFullPositionMap = true;
  773. m_deleteMap.LoadMap();
  774. m_deleteMap.TrackerReset(0);
  775. }
  776. // Determine the initial bookmark and update it for the cutlist
  777. m_bookmarkSeek = GetBookmark();
  778. m_deleteMap.TrackerReset(m_bookmarkSeek);
  779. m_deleteMap.TrackerWantsToJump(m_bookmarkSeek, m_bookmarkSeek);
  780. if (!gCoreContext->IsDatabaseIgnored() &&
  781. m_playerCtx->m_playingInfo->QueryAutoExpire() == kLiveTVAutoExpire)
  782. {
  783. gCoreContext->SaveSetting("DefaultChanid",
  784. static_cast<int>(m_playerCtx->m_playingInfo->GetChanID()));
  785. QString callsign = m_playerCtx->m_playingInfo->GetChannelSchedulingID();
  786. QString channum = m_playerCtx->m_playingInfo->GetChanNum();
  787. gCoreContext->SaveSetting("DefaultChanKeys", callsign + "[]:[]" + channum);
  788. if (m_playerCtx->m_recorder && m_playerCtx->m_recorder->IsValidRecorder())
  789. {
  790. uint cardid = static_cast<uint>(m_playerCtx->m_recorder->GetRecorderNumber());
  791. CardUtil::SetStartChannel(cardid, channum);
  792. }
  793. }
  794. return IsErrored() ? -1 : 0;
  795. }
  796. void MythPlayer::SetFramesPlayed(uint64_t played)
  797. {
  798. m_framesPlayed = played;
  799. if (m_videoOutput)
  800. m_videoOutput->SetFramesPlayed(played);
  801. }
  802. /** \fn MythPlayer::GetFreeVideoFrames(void)
  803. * \brief Returns the number of frames available for decoding onto.
  804. */
  805. int MythPlayer::GetFreeVideoFrames(void) const
  806. {
  807. if (m_videoOutput)
  808. return m_videoOutput->FreeVideoFrames();
  809. return 0;
  810. }
  811. /// \brief Return a list of frame types that can be rendered directly.
  812. VideoFrameType* MythPlayer::DirectRenderFormats(void)
  813. {
  814. static VideoFrameType s_defaultFormats[] = { FMT_YV12, FMT_NONE };
  815. if (m_videoOutput)
  816. return m_videoOutput->DirectRenderFormats();
  817. return &s_defaultFormats[0];
  818. }
  819. /**
  820. * \brief Removes a frame from the available queue for decoding onto.
  821. *
  822. * This places the frame in the limbo queue, from which frames are
  823. * removed if they are added to another queue. Normally a frame is
  824. * freed from limbo either by a ReleaseNextVideoFrame() or
  825. * DiscardVideoFrame() call; but limboed frames are also freed
  826. * during a seek reset.
  827. */
  828. VideoFrame *MythPlayer::GetNextVideoFrame(void)
  829. {
  830. if (m_videoOutput)
  831. return m_videoOutput->GetNextFreeFrame();
  832. return nullptr;
  833. }
  834. /** \fn MythPlayer::ReleaseNextVideoFrame(VideoFrame*, int64_t)
  835. * \brief Places frame on the queue of frames ready for display.
  836. */
  837. void MythPlayer::ReleaseNextVideoFrame(VideoFrame *buffer,
  838. int64_t timecode,
  839. bool wrap)
  840. {
  841. if (wrap)
  842. WrapTimecode(timecode, TC_VIDEO);
  843. buffer->timecode = timecode;
  844. m_latestVideoTimecode = timecode;
  845. if (m_videoOutput)
  846. m_videoOutput->ReleaseFrame(buffer);
  847. m_detectLetterBox->Detect(buffer);
  848. if (m_allPaused)
  849. CheckAspectRatio(buffer);
  850. }
  851. /** \fn MythPlayer::DiscardVideoFrame(VideoFrame*)
  852. * \brief Places frame in the available frames queue.
  853. */
  854. void MythPlayer::DiscardVideoFrame(VideoFrame *buffer)
  855. {
  856. if (m_videoOutput)
  857. m_videoOutput->DiscardFrame(buffer);
  858. }
  859. /** \fn MythPlayer::DiscardVideoFrames(bool)
  860. * \brief Places frames in the available frames queue.
  861. *
  862. * If called with 'Keyframe' set to false then all frames
  863. * not in use by the decoder are made available for decoding. Otherwise,
  864. * all frames are made available for decoding; this is only safe if
  865. * the next frame is a keyframe.
  866. *
  867. * \param Keyframe if this is true all frames are placed
  868. * in the available queue.
  869. * \param Flushed indicates that the decoder has been flushed AND the decoder
  870. * requires ALL frames to be released (used for VAAPI and VDPAU pause frames)
  871. */
  872. void MythPlayer::DiscardVideoFrames(bool KeyFrame, bool Flushed)
  873. {
  874. if (m_videoOutput)
  875. m_videoOutput->DiscardFrames(KeyFrame, Flushed);
  876. }
  877. bool MythPlayer::HasReachedEof(void) const
  878. {
  879. EofState eof = GetEof();
  880. if (eof != kEofStateNone && !m_allPaused)
  881. return true;
  882. if (GetEditMode())
  883. return false;
  884. if (m_liveTV)
  885. return false;
  886. if (!m_deleteMap.IsEmpty() && m_framesPlayed >= m_deleteMap.GetLastFrame())
  887. return true;
  888. return false;
  889. }
  890. VideoFrame *MythPlayer::GetCurrentFrame(int &w, int &h)
  891. {
  892. w = m_videoDim.width();
  893. h = m_videoDim.height();
  894. VideoFrame *retval = nullptr;
  895. m_vidExitLock.lock();
  896. if (m_videoOutput)
  897. retval = m_videoOutput->GetLastShownFrame();
  898. if (!retval)
  899. m_vidExitLock.unlock();
  900. return retval;
  901. }
  902. void MythPlayer::DeLimboFrame(VideoFrame *frame)
  903. {
  904. if (m_videoOutput)
  905. m_videoOutput->DeLimboFrame(frame);
  906. }
  907. void MythPlayer::ReleaseCurrentFrame(VideoFrame *frame)
  908. {
  909. if (frame)
  910. m_vidExitLock.unlock();
  911. }
  912. void MythPlayer::EmbedInWidget(QRect rect)
  913. {
  914. if (m_videoOutput)
  915. m_videoOutput->EmbedInWidget(rect);
  916. else
  917. {
  918. m_embedRect = rect;
  919. m_embedding = true;
  920. }
  921. }
  922. void MythPlayer::StopEmbedding(void)
  923. {
  924. if (m_videoOutput)
  925. {
  926. m_videoOutput->StopEmbedding();
  927. ReinitOSD();
  928. }
  929. else
  930. {
  931. m_embedRect = QRect();
  932. m_embedding = false;
  933. }
  934. }
  935. void MythPlayer::WindowResized(const QSize &new_size)
  936. {
  937. if (m_videoOutput)
  938. m_videoOutput->WindowResized(new_size);
  939. ReinitOSD();
  940. }
  941. void MythPlayer::EnableTeletext(int page)
  942. {
  943. QMutexLocker locker(&m_osdLock);
  944. if (!m_osd)
  945. return;
  946. m_osd->EnableTeletext(true, page);
  947. m_prevTextDisplayMode = m_textDisplayMode;
  948. m_textDisplayMode = kDisplayTeletextMenu;
  949. }
  950. void MythPlayer::DisableTeletext(void)
  951. {
  952. QMutexLocker locker(&m_osdLock);
  953. if (!m_osd)
  954. return;
  955. m_osd->EnableTeletext(false, 0);
  956. m_textDisplayMode = kDisplayNone;
  957. /* If subtitles are enabled before the teletext menu was displayed,
  958. re-enabled them. */
  959. if (m_prevTextDisplayMode & kDisplayAllCaptions)
  960. EnableCaptions(m_prevTextDisplayMode, false);
  961. }
  962. void MythPlayer::ResetTeletext(void)
  963. {
  964. QMutexLocker locker(&m_osdLock);
  965. if (!m_osd)
  966. return;
  967. m_osd->TeletextReset();
  968. }
  969. /** \fn MythPlayer::SetTeletextPage(uint)
  970. * \brief Set Teletext NUV Caption page
  971. */
  972. void MythPlayer::SetTeletextPage(uint page)
  973. {
  974. m_osdLock.lock();
  975. DisableCaptions(m_textDisplayMode);
  976. m_ttPageNum = page;
  977. m_cc608.SetTTPageNum(m_ttPageNum);
  978. m_textDisplayMode &= ~kDisplayAllCaptions;
  979. m_textDisplayMode |= kDisplayNUVTeletextCaptions;
  980. m_osdLock.unlock();
  981. }
  982. bool MythPlayer::HandleTeletextAction(const QString &action)
  983. {
  984. if (!(m_textDisplayMode & kDisplayTeletextMenu) || !m_osd)
  985. return false;
  986. bool handled = true;
  987. m_osdLock.lock();
  988. if (action == "MENU" || action == ACTION_TOGGLETT || action == "ESCAPE")
  989. DisableTeletext();
  990. else if (m_osd)
  991. handled = m_osd->TeletextAction(action);
  992. m_osdLock.unlock();
  993. return handled;
  994. }
  995. void MythPlayer::ResetCaptions(void)
  996. {
  997. QMutexLocker locker(&m_osdLock);
  998. if (!m_osd)
  999. return;
  1000. if (((m_textDisplayMode & kDisplayAVSubtitle) ||
  1001. (m_textDisplayMode & kDisplayTextSubtitle) ||
  1002. (m_textDisplayMode & kDisplayRawTextSubtitle) ||
  1003. (m_textDisplayMode & kDisplayDVDButton) ||
  1004. (m_textDisplayMode & kDisplayCC608) ||
  1005. (m_textDisplayMode & kDisplayCC708)))
  1006. {
  1007. m_osd->ClearSubtitles();
  1008. }
  1009. else if ((m_textDisplayMode & kDisplayTeletextCaptions) ||
  1010. (m_textDisplayMode & kDisplayNUVTeletextCaptions))
  1011. {
  1012. m_osd->TeletextClear();
  1013. }
  1014. }
  1015. void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
  1016. {
  1017. if (m_textDisplayMode)
  1018. m_prevNonzeroTextDisplayMode = m_textDisplayMode;
  1019. m_textDisplayMode &= ~mode;
  1020. ResetCaptions();
  1021. QMutexLocker locker(&m_osdLock);
  1022. bool newTextDesired = (m_textDisplayMode & kDisplayAllTextCaptions) != 0U;
  1023. // Only turn off textDesired if the Operator requested it.
  1024. if (osd_msg || newTextDesired)
  1025. m_textDesired = newTextDesired;
  1026. QString msg = "";
  1027. if (kDisplayNUVTeletextCaptions & mode)
  1028. msg += tr("TXT CAP");
  1029. if (kDisplayTeletextCaptions & mode)
  1030. {
  1031. if (m_decoder != nullptr)
  1032. msg += m_decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
  1033. GetTrack(kTrackTypeTeletextCaptions));
  1034. DisableTeletext();
  1035. }
  1036. int preserve = m_textDisplayMode & (kDisplayCC608 | kDisplayTextSubtitle |
  1037. kDisplayAVSubtitle | kDisplayCC708 |
  1038. kDisplayRawTextSubtitle);
  1039. if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
  1040. (kDisplayAVSubtitle & mode) || (kDisplayRawTextSubtitle & mode))
  1041. {
  1042. int type = toTrackType(mode);
  1043. if (m_decoder != nullptr)
  1044. msg += m_decoder->GetTrackDesc(type, GetTrack(type));
  1045. if (m_osd)
  1046. m_osd->EnableSubtitles(preserve);
  1047. }
  1048. if (kDisplayTextSubtitle & mode)
  1049. {
  1050. msg += tr("Text subtitles");
  1051. if (m_osd)
  1052. m_osd->EnableSubtitles(preserve);
  1053. }
  1054. if (!msg.isEmpty() && osd_msg)
  1055. {
  1056. msg += " " + tr("Off");
  1057. SetOSDMessage(msg, kOSDTimeout_Med);
  1058. }
  1059. }
  1060. void MythPlayer::EnableCaptions(uint mode, bool osd_msg)
  1061. {
  1062. QMutexLocker locker(&m_osdLock);
  1063. bool newTextDesired = (mode & kDisplayAllTextCaptions) != 0U;
  1064. // Only turn off textDesired if the Operator requested it.
  1065. if (osd_msg || newTextDesired)
  1066. m_textDesired = newTextDesired;
  1067. QString msg = "";
  1068. if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
  1069. (kDisplayAVSubtitle & mode) || kDisplayRawTextSubtitle & mode)
  1070. {
  1071. int type = toTrackType(mode);
  1072. if (m_decoder != nullptr)
  1073. msg += m_decoder->GetTrackDesc(type, GetTrack(type));
  1074. if (m_osd)
  1075. m_osd->EnableSubtitles(mode);
  1076. }
  1077. if (kDisplayTextSubtitle & mode)
  1078. {
  1079. if (m_osd)
  1080. m_osd->EnableSubtitles(kDisplayTextSubtitle);
  1081. msg += tr("Text subtitles");
  1082. }
  1083. if (kDisplayNUVTeletextCaptions & mode)
  1084. msg += tr("TXT %1").arg(m_ttPageNum, 3, 16);
  1085. if ((kDisplayTeletextCaptions & mode) && (m_decoder != nullptr))
  1086. {
  1087. msg += m_decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
  1088. GetTrack(kTrackTypeTeletextCaptions));
  1089. int page = m_decoder->GetTrackLanguageIndex(
  1090. kTrackTypeTeletextCaptions,
  1091. GetTrack(kTrackTypeTeletextCaptions));
  1092. EnableTeletext(page);
  1093. m_textDisplayMode = kDisplayTeletextCaptions;
  1094. }
  1095. msg += " " + tr("On");
  1096. LOG(VB_PLAYBACK, LOG_INFO, QString("EnableCaptions(%1) msg: %2")
  1097. .arg(mode).arg(msg));
  1098. m_textDisplayMode = mode;
  1099. if (m_textDisplayMode)
  1100. m_prevNonzeroTextDisplayMode = m_textDisplayMode;
  1101. if (osd_msg)
  1102. SetOSDMessage(msg, kOSDTimeout_Med);
  1103. }
  1104. bool MythPlayer::ToggleCaptions(void)
  1105. {
  1106. SetCaptionsEnabled(!((bool)m_textDisplayMode));
  1107. return m_textDisplayMode != 0U;
  1108. }
  1109. bool MythPlayer::ToggleCaptions(uint type)
  1110. {
  1111. QMutexLocker locker(&m_osdLock);
  1112. uint mode = toCaptionType(type);
  1113. uint origMode = m_textDisplayMode;
  1114. if (m_textDisplayMode)
  1115. DisableCaptions(m_textDisplayMode, (origMode & mode) != 0U);
  1116. if (origMode & mode)
  1117. return m_textDisplayMode != 0U;
  1118. if (mode)
  1119. EnableCaptions(mode);
  1120. return m_textDisplayMode != 0U;
  1121. }
  1122. void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
  1123. {
  1124. QMutexLocker locker(&m_osdLock);
  1125. m_enableCaptions = m_disableCaptions = false;
  1126. uint origMode = m_textDisplayMode;
  1127. // Only turn off textDesired if the Operator requested it.
  1128. if (osd_msg || enable)
  1129. m_textDesired = enable;
  1130. if (!enable)
  1131. {
  1132. DisableCaptions(origMode, osd_msg);
  1133. return;
  1134. }
  1135. int mode = HasCaptionTrack(m_prevNonzeroTextDisplayMode) ?
  1136. m_prevNonzeroTextDisplayMode : NextCaptionTrack(kDisplayNone);
  1137. if (origMode != (uint)mode)
  1138. {
  1139. DisableCaptions(origMode, false);
  1140. if (kDisplayNone == mode)
  1141. {
  1142. if (osd_msg)
  1143. {
  1144. SetOSDMessage(tr("No captions",
  1145. "CC/Teletext/Subtitle text not available"),
  1146. kOSDTimeout_Med);
  1147. }
  1148. LOG(VB_PLAYBACK, LOG_INFO,
  1149. "No captions available yet to enable.");
  1150. }
  1151. else if (mode)
  1152. {
  1153. EnableCaptions(mode, osd_msg);
  1154. }
  1155. }
  1156. ResetCaptions();
  1157. }
  1158. bool MythPlayer::GetCaptionsEnabled(void) const
  1159. {
  1160. return (kDisplayNUVTeletextCaptions == m_textDisplayMode) ||
  1161. (kDisplayTeletextCaptions == m_textDisplayMode) ||
  1162. (kDisplayAVSubtitle == m_textDisplayMode) ||
  1163. (kDisplayCC608 == m_textDisplayMode) ||
  1164. (kDisplayCC708 == m_textDisplayMode) ||
  1165. (kDisplayTextSubtitle == m_textDisplayMode) ||
  1166. (kDisplayRawTextSubtitle == m_textDisplayMode) ||
  1167. (kDisplayTeletextMenu == m_textDisplayMode);
  1168. }
  1169. QStringList MythPlayer::GetTracks(uint type)
  1170. {
  1171. if (m_decoder)
  1172. return m_decoder->GetTracks(type);
  1173. return QStringList();
  1174. }
  1175. uint MythPlayer::GetTrackCount(uint type)
  1176. {
  1177. if (m_decoder)
  1178. return m_decoder->GetTrackCount(type);
  1179. return 0;
  1180. }
  1181. int MythPlayer::SetTrack(uint type, int trackNo)
  1182. {
  1183. int ret = -1;
  1184. if (!m_decoder)
  1185. return ret;
  1186. ret = m_decoder->SetTrack(type, trackNo);
  1187. if (kTrackTypeAudio == type)
  1188. {
  1189. QString msg = "";
  1190. if (m_decoder)
  1191. SetOSDMessage(m_decoder->GetTrackDesc(type, GetTrack(type)),
  1192. kOSDTimeout_Med);
  1193. return ret;
  1194. }
  1195. uint subtype = toCaptionType(type);
  1196. if (subtype)
  1197. {
  1198. DisableCaptions(m_textDisplayMode, false);
  1199. EnableCaptions(subtype, true);
  1200. if ((kDisplayCC708 == subtype || kDisplayCC608 == subtype) && m_decoder)
  1201. {
  1202. int sid = m_decoder->GetTrackInfo(type, trackNo).m_stream_id;
  1203. if (sid >= 0)
  1204. {
  1205. (kDisplayCC708 == subtype) ? m_cc708.SetCurrentService(sid) :
  1206. m_cc608.SetMode(sid);
  1207. }
  1208. }
  1209. }
  1210. return ret;
  1211. }
  1212. /** \fn MythPlayer::TracksChanged(uint)
  1213. * \brief This tries to re-enable captions/subtitles if the user
  1214. * wants them and one of the captions/subtitles tracks has
  1215. * changed.
  1216. */
  1217. void MythPlayer::TracksChanged(uint trackType)
  1218. {
  1219. if (trackType >= kTrackTypeSubtitle &&
  1220. trackType <= kTrackTypeTeletextCaptions && m_textDesired)
  1221. {
  1222. m_enableCaptions = true;
  1223. }
  1224. }
  1225. void MythPlayer::EnableSubtitles(bool enable)
  1226. {
  1227. if (enable)
  1228. m_enableCaptions = true;
  1229. else
  1230. m_disableCaptions = true;
  1231. }
  1232. void MythPlayer::EnableForcedSubtitles(bool enable)
  1233. {
  1234. if (enable)
  1235. m_enableForcedSubtitles = true;
  1236. else
  1237. m_disableForcedSubtitles = true;
  1238. }
  1239. void MythPlayer::SetAllowForcedSubtitles(bool allow)
  1240. {
  1241. m_allowForcedSubtitles = allow;
  1242. SetOSDMessage(m_allowForcedSubtitles ?
  1243. tr("Forced Subtitles On") :
  1244. tr("Forced Subtitles Off"),
  1245. kOSDTimeout_Med);
  1246. }
  1247. void MythPlayer::DoDisableForcedSubtitles(void)
  1248. {
  1249. m_disableForcedSubtitles = false;
  1250. m_osdLock.lock();
  1251. if (m_osd)
  1252. m_osd->DisableForcedSubtitles();
  1253. m_osdLock.unlock();
  1254. }
  1255. void MythPlayer::DoEnableForcedSubtitles(void)
  1256. {
  1257. m_enableForcedSubtitles = false;
  1258. if (!m_allowForcedSubtitles)
  1259. return;
  1260. m_osdLock.lock();
  1261. if (m_osd)
  1262. m_osd->EnableSubtitles(kDisplayAVSubtitle, true /*forced only*/);
  1263. m_osdLock.unlock();
  1264. }
  1265. int MythPlayer::GetTrack(uint type)
  1266. {
  1267. if (m_decoder)
  1268. return m_decoder->GetTrack(type);
  1269. return -1;
  1270. }
  1271. int MythPlayer::ChangeTrack(uint type, int dir)
  1272. {
  1273. if (!m_decoder)
  1274. return -1;
  1275. int retval = m_decoder->ChangeTrack(type, dir);
  1276. if (retval >= 0)
  1277. {
  1278. SetOSDMessage(m_decoder->GetTrackDesc(type, GetTrack(type)),
  1279. kOSDTimeout_Med);
  1280. return retval;
  1281. }
  1282. return -1;
  1283. }
  1284. void MythPlayer::ChangeCaptionTrack(int dir)
  1285. {
  1286. if (!m_decoder || (dir < 0))
  1287. return;
  1288. if (!((m_textDisplayMode == kDisplayTextSubtitle) ||
  1289. (m_textDisplayMode == kDisplayNUVTeletextCaptions) ||
  1290. (m_textDisplayMode == kDisplayNone)))
  1291. {
  1292. int tracktype = toTrackType(m_textDisplayMode);
  1293. if (GetTrack(tracktype) < m_decoder->NextTrack(tracktype))
  1294. {
  1295. SetTrack(tracktype, m_decoder->NextTrack(tracktype));
  1296. return;
  1297. }
  1298. }
  1299. int nextmode = NextCaptionTrack(m_textDisplayMode);
  1300. if ((nextmode == kDisplayTextSubtitle) ||
  1301. (nextmode == kDisplayNUVTeletextCaptions) ||
  1302. (nextmode == kDisplayNone))
  1303. {
  1304. DisableCaptions(m_textDisplayMode, true);
  1305. if (nextmode != kDisplayNone)
  1306. EnableCaptions(nextmode, true);
  1307. }
  1308. else
  1309. {
  1310. int tracktype = toTrackType(nextmode);
  1311. int tracks = m_decoder->GetTrackCount(tracktype);
  1312. if (tracks)
  1313. {
  1314. DisableCaptions(m_textDisplayMode, true);
  1315. SetTrack(tracktype, 0);
  1316. }
  1317. }
  1318. }
  1319. bool MythPlayer::HasCaptionTrack(int mode)
  1320. {
  1321. if (mode == kDisplayNone)
  1322. return false;
  1323. if (((mode == kDisplayTextSubtitle) && HasTextSubtitles()) ||
  1324. (mode == kDisplayNUVTeletextCaptions))
  1325. {
  1326. return true;
  1327. }
  1328. if (!(mode == kDisplayTextSubtitle) &&
  1329. m_decoder->GetTrackCount(toTrackType(mode)))
  1330. {
  1331. return true;
  1332. }
  1333. return false;
  1334. }
  1335. int MythPlayer::NextCaptionTrack(int mode)
  1336. {
  1337. // Text->TextStream->708->608->AVSubs->Teletext->NUV->None
  1338. // NUV only offerred if PAL
  1339. bool pal = (m_vbiMode == VBIMode::PAL_TT);
  1340. int nextmode = kDisplayNone;
  1341. if (kDisplayTextSubtitle == mode)
  1342. nextmode = kDisplayRawTextSubtitle;
  1343. else if (kDisplayRawTextSubtitle == mode)
  1344. nextmode = kDisplayCC708;
  1345. else if (kDisplayCC708 == mode)
  1346. nextmode = kDisplayCC608;
  1347. else if (kDisplayCC608 == mode)
  1348. nextmode = kDisplayAVSubtitle;
  1349. else if (kDisplayAVSubtitle == mode)
  1350. nextmode = kDisplayTeletextCaptions;
  1351. else if (kDisplayTeletextCaptions == mode)
  1352. nextmode = pal ? kDisplayNUVTeletextCaptions : kDisplayNone;
  1353. else if ((kDisplayNUVTeletextCaptions == mode) && pal)
  1354. nextmode = kDisplayNone;
  1355. else if (kDisplayNone == mode)
  1356. nextmode = kDisplayTextSubtitle;
  1357. if (nextmode == kDisplayNone || HasCaptionTrack(nextmode))
  1358. return nextmode;
  1359. return NextCaptionTrack(nextmode);
  1360. }
  1361. void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
  1362. {
  1363. if (m_decoder)
  1364. m_fpsMultiplier = m_decoder->GetfpsMultiplier();
  1365. m_frameInterval = static_cast<int>(lround(1000000.0 * frame_period) / m_fpsMultiplier);
  1366. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval Interval:%1 Speed:%2 Scan:%3 (Multiplier: %4)")
  1367. .arg(m_frameInterval).arg(static_cast<double>(m_playSpeed)).arg(toQString(scan)).arg(m_fpsMultiplier));
  1368. }
  1369. void MythPlayer::ResetAVSync(void)
  1370. {
  1371. m_avsyncAvg = 0;
  1372. m_prevTc = 0;
  1373. m_rtcBase = 0;
  1374. m_priorAudioTimecode = 0;
  1375. m_priorVideoTimecode = 0;
  1376. m_lastFix = 0.0;
  1377. LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
  1378. }
  1379. void MythPlayer::InitAVSync(void)
  1380. {
  1381. m_rtcBase = 0;
  1382. m_priorAudioTimecode = 0;
  1383. m_priorVideoTimecode = 0;
  1384. m_lastFix = 0.0;
  1385. if (!FlagIsSet(kVideoIsNull))
  1386. {
  1387. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display Refresh Rate: %1 Video Frame Rate: %2")
  1388. .arg(1000000.0 / m_display->GetRefreshInterval(m_frameInterval), 0, 'f', 3)
  1389. .arg(1000000.0 / m_frameInterval, 0, 'f', 3));
  1390. SetFrameInterval(m_scan, 1.0 / (m_videoFrameRate * static_cast<double>(m_playSpeed)));
  1391. // try to get preferential scheduling, but ignore if we fail to.
  1392. myth_nice(-19);
  1393. }
  1394. }
  1395. void MythPlayer::WaitForTime(int64_t framedue)
  1396. {
  1397. int64_t unow = m_avTimer.nsecsElapsed() / 1000;
  1398. int64_t delay = framedue - unow;
  1399. if (delay > 0)
  1400. QThread::usleep(static_cast<unsigned long>(delay));
  1401. }
  1402. /*! \brief Keep PiP frame rate in sync with master framerate
  1403. *
  1404. * This is a simple frame rate tracker. If a frame is not due, then just keep
  1405. * the last displayed frame. Otherwise discard frame(s) that are too old.
  1406. */
  1407. bool MythPlayer::PipSync(void)
  1408. {
  1409. int maxtries = 6;
  1410. int64_t timenow = m_avTimer.nsecsElapsed() / 1000;
  1411. auto playspeed1000 = static_cast<int64_t>(1000.0F / m_playSpeed);
  1412. while (maxtries--)
  1413. {
  1414. if (!m_videoOutput->ValidVideoFrames())
  1415. return false;
  1416. m_videoOutput->StartDisplayingFrame();
  1417. VideoFrame *last = m_videoOutput->GetLastShownFrame();
  1418. if (!last)
  1419. return false;
  1420. m_videoOutput->ProcessFrame(last, nullptr, m_pipPlayers, m_scan);
  1421. int64_t videotimecode = last->timecode & 0x0000ffffffffffff;
  1422. if (videotimecode != last->timecode)
  1423. videotimecode = m_maxTcVal;
  1424. if (videotimecode == 0)
  1425. {
  1426. m_videoOutput->DoneDisplayingFrame(last);
  1427. return true;
  1428. }
  1429. m_maxTcVal = videotimecode;
  1430. if (m_rtcBase == 0)
  1431. m_rtcBase = timenow - (videotimecode * playspeed1000);
  1432. int64_t framedue = m_rtcBase + (videotimecode * playspeed1000);
  1433. if (framedue > timenow)
  1434. return true;
  1435. m_videoOutput->DoneDisplayingFrame(last);
  1436. }
  1437. return true;
  1438. }
  1439. #define AVSYNC_MAX_LATE 10000000
  1440. void MythPlayer::AVSync(VideoFrame *buffer)
  1441. {
  1442. if (m_videoOutput->IsErrored())
  1443. {
  1444. LOG(VB_GENERAL, LOG_ERR, LOC +
  1445. "AVSync: Unknown error in videoOutput, aborting playback.");
  1446. SetErrored(tr("Failed to initialize A/V Sync"));
  1447. return;
  1448. }
  1449. int64_t videotimecode = 0;
  1450. bool dropframe = false;
  1451. bool pause_audio = false;
  1452. int64_t framedue = 0;
  1453. int64_t audio_adjustment = 0;
  1454. int64_t unow = 0;
  1455. int64_t lateness = 0;
  1456. auto playspeed1000 = static_cast<int64_t>(1000.0F / m_playSpeed);
  1457. bool reset = false;
  1458. // controller gain
  1459. static float const s_av_control_gain = 0.4F;
  1460. // time weighted exponential filter coefficient
  1461. static float const s_sync_fc = 0.9F;
  1462. while (framedue == 0)
  1463. {
  1464. if (buffer)
  1465. {
  1466. videotimecode = buffer->timecode & 0x0000ffffffffffff;
  1467. // Detect bogus timecodes from DVD and ignore them.
  1468. if (videotimecode != buffer->timecode)
  1469. videotimecode = m_maxTcVal;
  1470. }
  1471. unow = m_avTimer.nsecsElapsed() / 1000;
  1472. if (!m_normalSpeed || FlagIsSet(kMusicChoice))
  1473. {
  1474. framedue = unow + m_frameInterval;
  1475. break;
  1476. }
  1477. // first time or after a seek - setup of m_rtcBase
  1478. if (m_rtcBase == 0)
  1479. {
  1480. // cater for DVB radio
  1481. if (videotimecode == 0)
  1482. videotimecode = m_audio.GetAudioTime();;
  1483. // cater for data only streams (i.e. MHEG)
  1484. bool dataonly = !m_audio.HasAudioIn() && m_videoDim.isEmpty();
  1485. // On first frame we get nothing, so exit out.
  1486. // FIXME - does this mean we skip the first frame? Should be avoidable.
  1487. if (videotimecode == 0 && !dataonly)
  1488. return;
  1489. m_rtcBase = unow - videotimecode * playspeed1000;
  1490. m_maxTcVal = 0;
  1491. m_maxTcFrames = 0;
  1492. m_numDroppedFrames = 0;
  1493. m_timeOffsetBase = static_cast<int64_t>(TranslatePositionFrameToMs(m_framesPlayed, false)) - videotimecode;
  1494. }
  1495. if (videotimecode == 0)
  1496. videotimecode = m_maxTcVal + m_frameInterval/1000;
  1497. int64_t tcincr = videotimecode - m_maxTcVal;
  1498. if (tcincr > 0 || tcincr < -100)
  1499. {
  1500. m_maxTcVal = videotimecode;
  1501. m_maxTcFrames = 0;
  1502. }
  1503. else
  1504. {
  1505. m_maxTcFrames++;
  1506. videotimecode = m_maxTcVal + m_maxTcFrames * m_frameInterval/1000;
  1507. }
  1508. if (m_playSpeed > 0.0F)
  1509. framedue = m_rtcBase + videotimecode * playspeed1000;
  1510. else
  1511. framedue = unow + m_frameInterval / 2;
  1512. // This code is disabled as it appears to cause multiple issues. It is
  1513. // retained for future reference...
  1514. // recalculate m_framesPlayed to conform to actual time code.
  1515. //m_framesPlayed = TranslatePositionMsToFrame(static_cast<uint64_t>(videotimecode + m_timeOffsetBase), false);
  1516. //m_decoder->SetFramesPlayed(static_cast<long long>(m_framesPlayed));
  1517. lateness = unow - framedue;
  1518. dropframe = false;
  1519. if (lateness > 30000)
  1520. dropframe = m_numDroppedFrames < 10;
  1521. if (lateness <= 30000 && m_priorAudioTimecode > 0
  1522. && m_priorVideoTimecode > 0)
  1523. {
  1524. // Get video in sync with audio
  1525. audio_adjustment = m_priorAudioTimecode - m_priorVideoTimecode;
  1526. // If there is excess audio - throw it away.
  1527. if (audio_adjustment < -200)
  1528. {
  1529. m_audio.Reset();
  1530. audio_adjustment = 0;
  1531. }
  1532. int sign = audio_adjustment < 0 ? -1 : 1;
  1533. float fix_amount = (m_lastFix * s_sync_fc + (1 - s_sync_fc) * audio_adjustment) * sign * s_av_control_gain;
  1534. m_lastFix = fix_amount * sign;
  1535. auto speedup1000 = static_cast<int64_t>(1000 * m_playSpeed);
  1536. m_rtcBase -= static_cast<int64_t>(1000000 * fix_amount * sign / speedup1000);
  1537. if (audio_adjustment * sign > 20)
  1538. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sync: Audio %1 by %2 ms")
  1539. .arg(audio_adjustment > 0 ? "ahead" : "behind").arg(abs(audio_adjustment)));
  1540. if (audio_adjustment > 200)
  1541. pause_audio = true;
  1542. }
  1543. // sanity check - reset m_rtcBase if time codes have gone crazy.
  1544. if ((lateness > AVSYNC_MAX_LATE || lateness < - AVSYNC_MAX_LATE))
  1545. {
  1546. framedue = 0;
  1547. m_rtcBase = 0;
  1548. if (reset)
  1549. {
  1550. LOG(VB_GENERAL, LOG_ERR, LOC +
  1551. QString("Resetting AV Sync2 failed, lateness = %1").arg(lateness));
  1552. SetErrored(tr("Failed to initialize A/V Sync"));
  1553. return;
  1554. }
  1555. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  1556. QString("Resetting AV Sync2, lateness = %1").arg(lateness));
  1557. reset = true;
  1558. }
  1559. }
  1560. m_priorVideoTimecode = videotimecode;
  1561. m_dispTimecode = videotimecode;
  1562. m_outputJmeter && m_outputJmeter->RecordCycleTime();
  1563. m_avsyncAvg = static_cast<int>(m_lastFix * 1000 / s_av_control_gain);
  1564. bool decoderdeint = buffer && buffer->already_deinterlaced;
  1565. FrameScanType ps = m_scan;
  1566. if (kScan_Detect == m_scan || kScan_Ignore == m_scan || decoderdeint)
  1567. {
  1568. ps = kScan_Progressive;
  1569. }
  1570. else if (buffer && is_interlaced(ps))
  1571. {
  1572. ps = kScan_Interlaced;
  1573. buffer->interlaced_reversed = (m_scan == kScan_Intr2ndField);
  1574. }
  1575. // only display the second field if needed
  1576. m_doubleFramerate = is_interlaced(ps) && m_lastDeinterlacer2x;
  1577. if (buffer && !dropframe)
  1578. {
  1579. m_osdLock.lock();
  1580. m_videoOutput->ProcessFrame(buffer, m_osd, m_pipPlayers, ps);
  1581. m_osdLock.unlock();
  1582. }
  1583. if (!pause_audio && m_avsyncAudioPaused)
  1584. {
  1585. m_avsyncAudioPaused = false;
  1586. m_audio.Pause(false);
  1587. }
  1588. if (pause_audio && !m_avsyncAudioPaused)
  1589. {
  1590. m_avsyncAudioPaused = true;
  1591. m_audio.Pause(true);
  1592. }
  1593. if (dropframe)
  1594. m_numDroppedFrames++;
  1595. else
  1596. m_numDroppedFrames = 0;
  1597. if (dropframe)
  1598. {
  1599. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  1600. QString("Dropping frame: Video is behind by %1ms").arg(lateness / 1000));
  1601. m_videoOutput->SetFramesPlayed(static_cast<long long>(++m_framesPlayed));
  1602. }
  1603. else if (!FlagIsSet(kVideoIsNull) && buffer)
  1604. {
  1605. // if we get here, we're actually going to do video output
  1606. m_osdLock.lock();
  1607. m_videoOutput->PrepareFrame(buffer, ps, m_osd);
  1608. m_osdLock.unlock();
  1609. // Don't wait for sync if this is a secondary PBP otherwise
  1610. // the primary PBP will become out of sync
  1611. if (!m_playerCtx->IsPBP() || m_playerCtx->IsPrimaryPBP())
  1612. WaitForTime(framedue);
  1613. // get time codes for calculating difference next time
  1614. m_priorAudioTimecode = m_audio.GetAudioTime();
  1615. m_videoOutput->Show(ps);
  1616. if (m_videoOutput->IsErrored())
  1617. {
  1618. LOG(VB_GENERAL, LOG_ERR, LOC + "Error condition detected "
  1619. "in videoOutput after Show(), aborting playback.");
  1620. SetErrored(tr("Serious error detected in Video Output"));
  1621. return;
  1622. }
  1623. if (m_doubleFramerate)
  1624. {
  1625. //second stage of deinterlacer processing
  1626. if (kScan_Interlaced == ps)
  1627. ps = kScan_Intr2ndField;
  1628. m_osdLock.lock();
  1629. // Only double rate CPU deinterlacers require an extra call to ProcessFrame
  1630. if (GetDoubleRateOption(buffer, DEINT_CPU) && !GetDoubleRateOption(buffer, DEINT_SHADER))
  1631. m_videoOutput->ProcessFrame(buffer, m_osd, m_pipPlayers, ps);
  1632. m_videoOutput->PrepareFrame(buffer, ps, m_osd);
  1633. m_osdLock.unlock();
  1634. // Display the second field
  1635. if (!m_playerCtx->IsPBP() || m_playerCtx->IsPrimaryPBP())
  1636. {
  1637. int64_t due = framedue + m_frameInterval / 2;
  1638. WaitForTime(due);
  1639. }
  1640. m_videoOutput->Show(ps);
  1641. }
  1642. }
  1643. else if (!m_playerCtx->IsPiPOrSecondaryPBP())
  1644. {
  1645. WaitForTime(framedue);
  1646. }
  1647. LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
  1648. QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 "
  1649. "audioadj=%4 tcoffset=%5 unow=%6 udue=%7 ")
  1650. .arg(m_priorAudioTimecode)
  1651. .arg(m_priorVideoTimecode)
  1652. .arg(m_frameInterval)
  1653. .arg(audio_adjustment)
  1654. .arg(m_tcWrap[TC_AUDIO])
  1655. .arg(unow)
  1656. .arg(framedue)
  1657. );
  1658. }
  1659. void MythPlayer::RefreshPauseFrame(void)
  1660. {
  1661. if (m_needNewPauseFrame)
  1662. {
  1663. if (m_videoOutput->ValidVideoFrames())
  1664. {
  1665. m_videoOutput->UpdatePauseFrame(m_dispTimecode, m_scan);
  1666. m_needNewPauseFrame = false;
  1667. if (m_deleteMap.IsEditing())
  1668. {
  1669. m_osdLock.lock();
  1670. if (m_osd)
  1671. DeleteMap::UpdateOSD(GetLatestVideoTimecode(), m_osd);
  1672. m_osdLock.unlock();
  1673. }
  1674. }
  1675. else
  1676. {
  1677. m_decodeOneFrame = true;
  1678. }
  1679. }
  1680. }
  1681. void MythPlayer::DisplayPauseFrame(void)
  1682. {
  1683. if (!m_videoOutput)
  1684. return;
  1685. if (m_videoOutput->IsErrored())
  1686. {
  1687. SetErrored(tr("Serious error detected in Video Output"));
  1688. return;
  1689. }
  1690. // clear the buffering state
  1691. SetBuffering(false);
  1692. RefreshPauseFrame();
  1693. PreProcessNormalFrame(); // Allow interactiveTV to draw on pause frame
  1694. FrameScanType scan = (kScan_Detect == m_scan || kScan_Ignore == m_scan) ? kScan_Progressive : m_scan;
  1695. m_osdLock.lock();
  1696. m_videoOutput->ProcessFrame(nullptr, m_osd, m_pipPlayers, scan);
  1697. m_videoOutput->PrepareFrame(nullptr, scan, m_osd);
  1698. m_osdLock.unlock();
  1699. m_videoOutput->Show(scan);
  1700. }
  1701. void MythPlayer::SetBuffering(bool new_buffering)
  1702. {
  1703. if (!m_buffering && new_buffering)
  1704. {
  1705. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waiting for video buffers...");
  1706. m_buffering = true;
  1707. m_bufferingStart = QTime::currentTime();
  1708. m_bufferingLastMsg = QTime::currentTime();
  1709. }
  1710. else if (m_buffering && !new_buffering)
  1711. {
  1712. m_buffering = false;
  1713. }
  1714. }
  1715. // For debugging playback set this to increase the timeout so that
  1716. // playback does not fail if stepping through code.
  1717. // Set PREBUFFERDEBUG to any value and you will get 30 minutes.
  1718. static char *preBufferDebug = getenv("PREBUFFERDEBUG");
  1719. bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
  1720. {
  1721. if (!m_videoOutput)
  1722. return false;
  1723. if (!(min_buffers ? (m_videoOutput->ValidVideoFrames() >= min_buffers) :
  1724. (GetEof() != kEofStateNone) || m_videoOutput->EnoughDecodedFrames()))
  1725. {
  1726. SetBuffering(true);
  1727. // This piece of code is to address the problem, when starting
  1728. // Live TV, of jerking and stuttering. Without this code
  1729. // that could go on forever, but is cured by a pause and play.
  1730. // This code inserts a brief pause and play when the potential
  1731. // for the jerking is detected.
  1732. bool watchingTV = IsWatchingInprogress();
  1733. if ((m_liveTV || watchingTV) && !FlagIsSet(kMusicChoice))
  1734. {
  1735. uint64_t frameCount = GetCurrentFrameCount();
  1736. uint64_t framesLeft = frameCount - m_framesPlayed;
  1737. auto margin = static_cast<uint64_t>(m_videoFrameRate * 3);
  1738. if (framesLeft < margin)
  1739. {
  1740. if (m_rtcBase)
  1741. {
  1742. LOG(VB_PLAYBACK, LOG_NOTICE, LOC + "Pause to allow live tv catch up");
  1743. LOG(VB_PLAYBACK, LOG_NOTICE, LOC + QString("Played: %1 Avail: %2 Buffered: %3 Margin: %4")
  1744. .arg(m_framesPlayed).arg(frameCount)
  1745. .arg(m_videoOutput->ValidVideoFrames()).arg(margin));
  1746. }
  1747. m_audio.Pause(true);
  1748. m_avsyncAudioPaused = true;
  1749. m_rtcBase = 0;
  1750. }
  1751. }
  1752. usleep(static_cast<uint>(m_frameInterval >> 3));
  1753. int waited_for = m_bufferingStart.msecsTo(QTime::currentTime());
  1754. int last_msg = m_bufferingLastMsg.msecsTo(QTime::currentTime());
  1755. if (last_msg > 100 && !FlagIsSet(kMusicChoice))
  1756. {
  1757. if (++m_bufferingCounter == 10)
  1758. LOG(VB_GENERAL, LOG_NOTICE, LOC +
  1759. "To see more buffering messages use -v playback");
  1760. if (m_bufferingCounter >= 10)
  1761. {
  1762. LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
  1763. QString("Waited %1ms for video buffers %2")
  1764. .arg(waited_for).arg(m_videoOutput->GetFrameStatus()));
  1765. }
  1766. else
  1767. {
  1768. LOG(VB_GENERAL, LOG_NOTICE, LOC +
  1769. QString("Waited %1ms for video buffers %2")
  1770. .arg(waited_for).arg(m_videoOutput->GetFrameStatus()));
  1771. }
  1772. m_bufferingLastMsg = QTime::currentTime();
  1773. if (m_audio.IsBufferAlmostFull() && m_framesPlayed < 5
  1774. && gCoreContext->GetBoolSetting("MusicChoiceEnabled", false))
  1775. {
  1776. m_playerFlags = static_cast<PlayerFlags>(m_playerFlags | kMusicChoice);
  1777. LOG(VB_GENERAL, LOG_NOTICE, LOC +
  1778. "Music Choice program detected - disabling AV Sync.");
  1779. m_avsyncAudioPaused = false;
  1780. m_audio.Pause(false);
  1781. }
  1782. if (waited_for > 7000 && m_audio.IsBufferAlmostFull()
  1783. && !FlagIsSet(kMusicChoice))
  1784. {
  1785. // We are likely to enter this condition
  1786. // if the audio buffer was too full during GetFrame in AVFD
  1787. LOG(VB_GENERAL, LOG_NOTICE, LOC + "Resetting audio buffer");
  1788. m_audio.Reset();
  1789. }
  1790. // Finish audio pause for sync after 1 second
  1791. // in case of infrequent video frames (e.g. music choice)
  1792. if (m_avsyncAudioPaused && waited_for > 1000)
  1793. {
  1794. m_avsyncAudioPaused = false;
  1795. m_audio.Pause(false);
  1796. }
  1797. }
  1798. int msecs = 500;
  1799. if (preBufferDebug)
  1800. msecs = 1800000;
  1801. if ((waited_for > msecs /*500*/) && !m_videoOutput->EnoughFreeFrames())
  1802. {
  1803. LOG(VB_GENERAL, LOG_NOTICE, LOC +
  1804. "Timed out waiting for frames, and"
  1805. "\n\t\t\tthere are not enough free frames. "
  1806. "Discarding buffered frames.");
  1807. // This call will result in some ugly frames, but allows us
  1808. // to recover from serious problems if frames get leaked.
  1809. DiscardVideoFrames(true, true);
  1810. }
  1811. msecs = 30000;
  1812. if (preBufferDebug)
  1813. msecs = 1800000;
  1814. if (waited_for > msecs /*30000*/) // 30 seconds for internet streamed media
  1815. {
  1816. LOG(VB_GENERAL, LOG_ERR, LOC +
  1817. "Waited too long for decoder to fill video buffers. Exiting..");
  1818. SetErrored(tr("Video frame buffering failed too many times."));
  1819. }
  1820. return false;
  1821. }
  1822. if (!m_avsyncAudioPaused)
  1823. m_audio.Pause(false);
  1824. SetBuffering(false);
  1825. return true;
  1826. }
  1827. void MythPlayer::CheckAspectRatio(VideoFrame* frame)
  1828. {
  1829. if (!frame)
  1830. return;
  1831. if (!qFuzzyCompare(frame->aspect, m_videoAspect) && frame->aspect > 0.0F)
  1832. {
  1833. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  1834. QString("Video Aspect ratio changed from %1 to %2")
  1835. .arg(m_videoAspect).arg(frame->aspect));
  1836. m_videoAspect = frame->aspect;
  1837. if (m_videoOutput)
  1838. {
  1839. m_videoOutput->VideoAspectRatioChanged(m_videoAspect);
  1840. ReinitOSD();
  1841. }
  1842. }
  1843. }
  1844. void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
  1845. {
  1846. if (m_allPaused)
  1847. return;
  1848. bool ispip = m_playerCtx->IsPIP();
  1849. if (ispip)
  1850. {
  1851. if (!m_videoOutput->ValidVideoFrames())
  1852. return;
  1853. }
  1854. else if (check_prebuffer && !PrebufferEnoughFrames())
  1855. {
  1856. return;
  1857. }
  1858. // clear the buffering state
  1859. SetBuffering(false);
  1860. // If PiP then release the last shown frame to the decoding queue
  1861. if (ispip)
  1862. if (!PipSync())
  1863. return;
  1864. // retrieve the next frame
  1865. m_videoOutput->StartDisplayingFrame();
  1866. VideoFrame *frame = m_videoOutput->GetLastShownFrame();
  1867. // Check aspect ratio
  1868. CheckAspectRatio(frame);
  1869. if (m_decoder && m_fpsMultiplier != m_decoder->GetfpsMultiplier())
  1870. UpdateFFRewSkip();
  1871. // Player specific processing (dvd, bd, mheg etc)
  1872. PreProcessNormalFrame();
  1873. // handle scan type changes
  1874. AutoDeint(frame);
  1875. m_detectLetterBox->SwitchTo(frame);
  1876. if (!ispip)
  1877. AVSync(frame);
  1878. // Update details for debug OSD
  1879. m_lastDeinterlacer = frame->deinterlace_inuse;
  1880. m_lastDeinterlacer2x = frame->deinterlace_inuse2x;
  1881. // We use the underlying pix_fmt as it retains the distinction between hardware
  1882. // and software frames for decode only decoders.
  1883. m_lastFrameCodec = PixelFormatToFrameType(static_cast<AVPixelFormat>(frame->pix_fmt));
  1884. // If PiP then keep this frame for MythPlayer::GetCurrentFrame
  1885. if (!ispip)
  1886. m_videoOutput->DoneDisplayingFrame(frame);
  1887. }
  1888. void MythPlayer::PreProcessNormalFrame(void)
  1889. {
  1890. #ifdef USING_MHEG
  1891. // handle Interactive TV
  1892. if (GetInteractiveTV())
  1893. {
  1894. m_osdLock.lock();
  1895. m_itvLock.lock();
  1896. if (m_osd && m_videoOutput->GetOSDPainter())
  1897. {
  1898. InteractiveScreen *window =
  1899. dynamic_cast<InteractiveScreen *>(m_osd->GetWindow(OSD_WIN_INTERACT));
  1900. if ((m_interactiveTV->ImageHasChanged() || !m_itvVisible) && window)
  1901. {
  1902. m_interactiveTV->UpdateOSD(window, m_videoOutput->GetOSDPainter());
  1903. m_itvVisible = true;
  1904. }
  1905. }
  1906. m_itvLock.unlock();
  1907. m_osdLock.unlock();
  1908. }
  1909. #endif // USING_MHEG
  1910. }
  1911. bool MythPlayer::CanSupportDoubleRate(void)
  1912. {
  1913. int refreshinterval = 1;
  1914. if (m_display)
  1915. refreshinterval = m_display->GetRefreshInterval(m_frameInterval);
  1916. // At this point we may not have the correct frame rate.
  1917. // Since interlaced is always at 25 or 30 fps, if the interval
  1918. // is less than 30000 (33fps) it must be representing one
  1919. // field and not one frame, so multiply by 2.
  1920. int realfi = m_frameInterval;
  1921. if (m_frameInterval < 30000)
  1922. realfi = m_frameInterval * 2;
  1923. return ((realfi / 2.0) > (refreshinterval * 0.995));
  1924. }
  1925. void MythPlayer::EnableFrameRateMonitor(bool enable)
  1926. {
  1927. if (!m_outputJmeter)
  1928. return;
  1929. bool verbose = VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_ANY);
  1930. double rate = enable ? m_videoFrameRate : verbose ? (m_videoFrameRate * 4) : 0.0;
  1931. m_outputJmeter->SetNumCycles(static_cast<int>(rate));
  1932. }
  1933. void MythPlayer::ForceDeinterlacer(bool DoubleRate, MythDeintType Deinterlacer)
  1934. {
  1935. if (m_videoOutput)
  1936. m_videoOutput->SetDeinterlacing(true, DoubleRate, Deinterlacer);
  1937. }
  1938. void MythPlayer::VideoStart(void)
  1939. {
  1940. if (!FlagIsSet(kVideoIsNull) && !m_playerCtx->IsPIP())
  1941. {
  1942. QRect visible;
  1943. QRect total;
  1944. float aspect = NAN;
  1945. float scaling = NAN;
  1946. m_osdLock.lock();
  1947. m_osd = new OSD(this, m_tv, m_videoOutput->GetOSDPainter());
  1948. m_videoOutput->GetOSDBounds(total, visible, aspect, scaling, 1.0F);
  1949. m_osd->Init(visible, aspect);
  1950. m_osd->EnableSubtitles(kDisplayNone);
  1951. #ifdef USING_MHEG
  1952. if (GetInteractiveTV())
  1953. {
  1954. QMutexLocker locker(&m_itvLock);
  1955. m_interactiveTV->Reinit(total, visible, aspect);
  1956. }
  1957. #endif // USING_MHEG
  1958. // If there is a forced text subtitle track (which is possible
  1959. // in e.g. a .mkv container), and forced subtitles are
  1960. // allowed, then start playback with that subtitle track
  1961. // selected. Otherwise, use the frontend settings to decide
  1962. // which captions/subtitles (if any) to enable at startup.
  1963. // TODO: modify the fix to #10735 to use this approach
  1964. // instead.
  1965. bool hasForcedTextTrack = false;
  1966. uint forcedTrackNumber = 0;
  1967. if (GetAllowForcedSubtitles())
  1968. {
  1969. uint numTextTracks = m_decoder->GetTrackCount(kTrackTypeRawText);
  1970. for (uint i = 0; !hasForcedTextTrack && i < numTextTracks; ++i)
  1971. {
  1972. if (m_decoder->GetTrackInfo(kTrackTypeRawText, i).m_forced)
  1973. {
  1974. hasForcedTextTrack = true;
  1975. forcedTrackNumber = i;
  1976. }
  1977. }
  1978. }
  1979. if (hasForcedTextTrack)
  1980. SetTrack(kTrackTypeRawText, forcedTrackNumber);
  1981. else
  1982. SetCaptionsEnabled(m_captionsEnabledbyDefault, false);
  1983. m_osdLock.unlock();
  1984. }
  1985. SetPlaying(true);
  1986. ClearAfterSeek(false);
  1987. m_avsyncAvg = 0; // Frames till next sync check
  1988. EnableFrameRateMonitor();
  1989. // Default to interlaced playback but set the tracker to progressive
  1990. // Enable autodetection of interlaced/progressive from video stream
  1991. // Previously we set to interlaced and the scan tracker to 2 but this
  1992. // mis-'detected' a number of streams as interlaced when they are progressive.
  1993. // This significantly reduces the number of errors and also ensures we do not
  1994. // needlessly setup deinterlacers - which may consume significant resources.
  1995. // We set to interlaced for those streams whose frame rate is initially detected
  1996. // as e.g. 59.9 when it is actually 29.97 interlaced.
  1997. m_scan = kScan_Interlaced;
  1998. m_scanLocked = false;
  1999. m_doubleFramerate = false;
  2000. m_scanTracker = -2;
  2001. if (!FlagIsSet(kVideoIsNull) && m_videoOutput)
  2002. {
  2003. m_doubleFramerate = CanSupportDoubleRate();
  2004. m_videoOutput->SetDeinterlacing(true, m_doubleFramerate);
  2005. }
  2006. InitAVSync();
  2007. AutoVisualise();
  2008. }
  2009. bool MythPlayer::VideoLoop(void)
  2010. {
  2011. ProcessCallbacks();
  2012. if (m_videoPaused || m_isDummy)
  2013. {
  2014. switch (m_playerCtx->GetPIPState())
  2015. {
  2016. case kPIPonTV:
  2017. case kPBPRight:
  2018. break;
  2019. case kPIPOff:
  2020. case kPIPStandAlone:
  2021. case kPBPLeft: // PrimaryBPB
  2022. usleep(m_frameInterval);
  2023. break;
  2024. }
  2025. DisplayPauseFrame();
  2026. }
  2027. else
  2028. DisplayNormalFrame();
  2029. if (FlagIsSet(kVideoIsNull) && m_decoder)
  2030. m_decoder->UpdateFramesPlayed();
  2031. else if (m_decoder && m_decoder->GetEof() != kEofStateNone)
  2032. ++m_framesPlayed;
  2033. else
  2034. m_framesPlayed = m_videoOutput->GetFramesPlayed();
  2035. return !IsErrored();
  2036. }
  2037. void MythPlayer::VideoEnd(void)
  2038. {
  2039. m_osdLock.lock();
  2040. m_vidExitLock.lock();
  2041. delete m_osd;
  2042. delete m_videoOutput;
  2043. m_osd = nullptr;
  2044. m_videoOutput = nullptr;
  2045. m_vidExitLock.unlock();
  2046. m_osdLock.unlock();
  2047. }
  2048. bool MythPlayer::FastForward(float seconds)
  2049. {
  2050. if (!m_videoOutput)
  2051. return false;
  2052. if (m_ffTime <= 0)
  2053. {
  2054. float current = ComputeSecs(m_framesPlayed, true);
  2055. float dest = current + seconds;
  2056. float length = ComputeSecs(m_totalFrames, true);
  2057. if (dest > length)
  2058. {
  2059. int64_t pos = TranslatePositionMsToFrame(seconds * 1000, false);
  2060. if (CalcMaxFFTime(pos) < 0)
  2061. return true;
  2062. // Reach end of recording, go to 1 or 3s before the end
  2063. dest = (m_liveTV || IsWatchingInprogress()) ? -3.0 : -1.0;
  2064. }
  2065. uint64_t target = FindFrame(dest, true);
  2066. m_ffTime = target - m_framesPlayed;
  2067. }
  2068. return m_ffTime > CalcMaxFFTime(m_ffTime, false);
  2069. }
  2070. bool MythPlayer::Rewind(float seconds)
  2071. {
  2072. if (!m_videoOutput)
  2073. return false;
  2074. if (m_rewindTime <= 0)
  2075. {
  2076. float current = ComputeSecs(m_framesPlayed, true);
  2077. float dest = current - seconds;
  2078. if (dest < 0)
  2079. {
  2080. int64_t pos = TranslatePositionMsToFrame(seconds * 1000, false);
  2081. if (CalcRWTime(pos) < 0)
  2082. return true;
  2083. dest = 0;
  2084. }
  2085. uint64_t target = FindFrame(dest, true);
  2086. m_rewindTime = m_framesPlayed - target;
  2087. }
  2088. return (uint64_t)m_rewindTime >= m_framesPlayed;
  2089. }
  2090. bool MythPlayer::JumpToFrame(uint64_t frame)
  2091. {
  2092. if (!m_videoOutput)
  2093. return false;
  2094. bool ret = false;
  2095. m_ffTime = m_rewindTime = 0;
  2096. if (frame > m_framesPlayed)
  2097. {
  2098. m_ffTime = frame - m_framesPlayed;
  2099. ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
  2100. }
  2101. else if (frame < m_framesPlayed)
  2102. {
  2103. m_rewindTime = m_framesPlayed - frame;
  2104. ret = m_ffTime > CalcMaxFFTime(m_ffTime, false);
  2105. }
  2106. return ret;
  2107. }
  2108. void MythPlayer::JumpChapter(int chapter)
  2109. {
  2110. if (m_jumpChapter == 0)
  2111. m_jumpChapter = chapter;
  2112. }
  2113. void MythPlayer::ResetPlaying(bool resetframes)
  2114. {
  2115. ClearAfterSeek();
  2116. m_ffrewSkip = 1;
  2117. if (resetframes)
  2118. m_framesPlayed = 0;
  2119. if (m_decoder)
  2120. {
  2121. m_decoder->Reset(true, true, true);
  2122. if (m_decoder->IsErrored())
  2123. SetErrored("Unable to reset video decoder");
  2124. }
  2125. }
  2126. void MythPlayer::CheckTVChain(void)
  2127. {
  2128. bool last = !(m_playerCtx->m_tvchain->HasNext());
  2129. SetWatchingRecording(last);
  2130. }
  2131. void MythPlayer::SwitchToProgram(void)
  2132. {
  2133. if (!IsReallyNearEnd())
  2134. return;
  2135. LOG(VB_PLAYBACK, LOG_INFO, LOC + "SwitchToProgram - start");
  2136. bool discontinuity = false;
  2137. bool newtype = false;
  2138. int newid = -1;
  2139. ProgramInfo *pginfo = m_playerCtx->m_tvchain->GetSwitchProgram(
  2140. discontinuity, newtype, newid);
  2141. if (!pginfo)
  2142. return;
  2143. bool newIsDummy = m_playerCtx->m_tvchain->GetInputType(newid) == "DUMMY";
  2144. SetPlayingInfo(*pginfo);
  2145. Pause();
  2146. ChangeSpeed();
  2147. // Release all frames to ensure the current decoder resources are released
  2148. DiscardVideoFrames(true, true);
  2149. if (newIsDummy)
  2150. {
  2151. OpenDummy();
  2152. ResetPlaying();
  2153. SetEof(kEofStateNone);
  2154. delete pginfo;
  2155. return;
  2156. }
  2157. if (m_playerCtx->m_buffer->GetType() == kMythBufferMHEG)
  2158. {
  2159. // Restore original ringbuffer
  2160. auto *ic = dynamic_cast<MythInteractiveBuffer*>(m_playerCtx->m_buffer);
  2161. if (ic)
  2162. m_playerCtx->m_buffer = ic->TakeBuffer();
  2163. delete ic;
  2164. }
  2165. m_playerCtx->m_buffer->OpenFile(
  2166. pginfo->GetPlaybackURL(), MythMediaBuffer::kLiveTVOpenTimeout);
  2167. if (!m_playerCtx->m_buffer->IsOpen())
  2168. {
  2169. LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram's OpenFile failed " +
  2170. QString("(input type: %1).")
  2171. .arg(m_playerCtx->m_tvchain->GetInputType(newid)));
  2172. LOG(VB_GENERAL, LOG_ERR, m_playerCtx->m_tvchain->toString());
  2173. SetEof(kEofStateImmediate);
  2174. SetErrored(tr("Error opening switch program buffer"));
  2175. delete pginfo;
  2176. return;
  2177. }
  2178. if (GetEof() != kEofStateNone)
  2179. {
  2180. discontinuity = true;
  2181. ResetCaptions();
  2182. }
  2183. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SwitchToProgram(void) "
  2184. "discont: %1 newtype: %2 newid: %3 decoderEof: %4")
  2185. .arg(discontinuity).arg(newtype).arg(newid).arg(GetEof()));
  2186. if (discontinuity || newtype)
  2187. {
  2188. m_playerCtx->m_tvchain->SetProgram(*pginfo);
  2189. if (m_decoder)
  2190. m_decoder->SetProgramInfo(*pginfo);
  2191. m_playerCtx->m_buffer->Reset(true);
  2192. if (newtype)
  2193. {
  2194. if (OpenFile() < 0)
  2195. SetErrored(tr("Error opening switch program file"));
  2196. }
  2197. else
  2198. ResetPlaying();
  2199. }
  2200. else
  2201. {
  2202. m_playerCtx->SetPlayerChangingBuffers(true);
  2203. if (m_decoder)
  2204. {
  2205. m_decoder->SetReadAdjust(m_playerCtx->m_buffer->SetAdjustFilesize());
  2206. m_decoder->SetWaitForChange();
  2207. }
  2208. }
  2209. delete pginfo;
  2210. if (IsErrored())
  2211. {
  2212. LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram failed.");
  2213. SetEof(kEofStateDelayed);
  2214. return;
  2215. }
  2216. SetEof(kEofStateNone);
  2217. // the bitrate is reset by m_playerCtx->m_buffer->OpenFile()...
  2218. if (m_decoder)
  2219. m_playerCtx->m_buffer->UpdateRawBitrate(m_decoder->GetRawBitrate());
  2220. m_playerCtx->m_buffer->Unpause();
  2221. if (discontinuity || newtype)
  2222. {
  2223. CheckTVChain();
  2224. m_forcePositionMapSync = true;
  2225. }
  2226. Play();
  2227. LOG(VB_PLAYBACK, LOG_INFO, LOC + "SwitchToProgram - end");
  2228. }
  2229. // This is called from decoder thread. Set an indicator that will
  2230. // be checked and actioned in the player thread.
  2231. void MythPlayer::FileChangedCallback(void)
  2232. {
  2233. LOG(VB_PLAYBACK, LOG_INFO, LOC + "FileChangedCallback");
  2234. m_fileChanged = true;
  2235. }
  2236. // Called from the player thread.
  2237. void MythPlayer::FileChanged(void)
  2238. {
  2239. m_fileChanged = false;
  2240. LOG(VB_PLAYBACK, LOG_INFO, LOC + "FileChanged");
  2241. Pause();
  2242. ChangeSpeed();
  2243. if (dynamic_cast<AvFormatDecoder *>(m_decoder))
  2244. m_playerCtx->m_buffer->Reset(false, true);
  2245. else
  2246. m_playerCtx->m_buffer->Reset(false, true, true);
  2247. SetEof(kEofStateNone);
  2248. Play();
  2249. m_playerCtx->SetPlayerChangingBuffers(false);
  2250. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  2251. m_playerCtx->m_tvchain->SetProgram(*m_playerCtx->m_playingInfo);
  2252. if (m_decoder)
  2253. m_decoder->SetProgramInfo(*m_playerCtx->m_playingInfo);
  2254. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  2255. CheckTVChain();
  2256. m_forcePositionMapSync = true;
  2257. }
  2258. void MythPlayer::JumpToProgram(void)
  2259. {
  2260. LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToProgram - start");
  2261. bool discontinuity = false;
  2262. bool newtype = false;
  2263. int newid = -1;
  2264. long long nextpos = m_playerCtx->m_tvchain->GetJumpPos();
  2265. ProgramInfo *pginfo = m_playerCtx->m_tvchain->GetSwitchProgram(
  2266. discontinuity, newtype, newid);
  2267. if (!pginfo)
  2268. return;
  2269. m_inJumpToProgramPause = true;
  2270. bool newIsDummy = m_playerCtx->m_tvchain->GetInputType(newid) == "DUMMY";
  2271. SetPlayingInfo(*pginfo);
  2272. Pause();
  2273. ChangeSpeed();
  2274. ResetCaptions();
  2275. // Release all frames to ensure the current decoder resources are released
  2276. DiscardVideoFrames(true, true);
  2277. m_playerCtx->m_tvchain->SetProgram(*pginfo);
  2278. m_playerCtx->m_buffer->Reset(true);
  2279. if (newIsDummy)
  2280. {
  2281. OpenDummy();
  2282. ResetPlaying();
  2283. SetEof(kEofStateNone);
  2284. delete pginfo;
  2285. m_inJumpToProgramPause = false;
  2286. return;
  2287. }
  2288. SendMythSystemPlayEvent("PLAY_CHANGED", pginfo);
  2289. if (m_playerCtx->m_buffer->GetType() == kMythBufferMHEG)
  2290. {
  2291. // Restore original ringbuffer
  2292. auto *ic = dynamic_cast<MythInteractiveBuffer*>(m_playerCtx->m_buffer);
  2293. if (ic)
  2294. m_playerCtx->m_buffer = ic->TakeBuffer();
  2295. delete ic;
  2296. }
  2297. m_playerCtx->m_buffer->OpenFile(pginfo->GetPlaybackURL(), MythMediaBuffer::kLiveTVOpenTimeout);
  2298. QString subfn = m_playerCtx->m_buffer->GetSubtitleFilename();
  2299. TVState desiredState = m_playerCtx->GetState();
  2300. bool isInProgress = (desiredState == kState_WatchingRecording ||
  2301. desiredState == kState_WatchingLiveTV);
  2302. if (GetSubReader())
  2303. GetSubReader()->LoadExternalSubtitles(subfn, isInProgress &&
  2304. !subfn.isEmpty());
  2305. if (!m_playerCtx->m_buffer->IsOpen())
  2306. {
  2307. LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToProgram's OpenFile failed " +
  2308. QString("(input type: %1).")
  2309. .arg(m_playerCtx->m_tvchain->GetInputType(newid)));
  2310. LOG(VB_GENERAL, LOG_ERR, m_playerCtx->m_tvchain->toString());
  2311. SetEof(kEofStateImmediate);
  2312. SetErrored(tr("Error opening jump program file buffer"));
  2313. delete pginfo;
  2314. m_inJumpToProgramPause = false;
  2315. return;
  2316. }
  2317. bool wasDummy = m_isDummy;
  2318. if (newtype || wasDummy)
  2319. {
  2320. if (OpenFile() < 0)
  2321. SetErrored(tr("Error opening jump program file"));
  2322. }
  2323. else
  2324. ResetPlaying();
  2325. if (IsErrored() || !m_decoder)
  2326. {
  2327. LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToProgram failed.");
  2328. if (!IsErrored())
  2329. SetErrored(tr("Error reopening video decoder"));
  2330. delete pginfo;
  2331. m_inJumpToProgramPause = false;
  2332. return;
  2333. }
  2334. SetEof(kEofStateNone);
  2335. // the bitrate is reset by m_playerCtx->m_buffer->OpenFile()...
  2336. m_playerCtx->m_buffer->UpdateRawBitrate(m_decoder->GetRawBitrate());
  2337. m_playerCtx->m_buffer->IgnoreLiveEOF(false);
  2338. m_decoder->SetProgramInfo(*pginfo);
  2339. delete pginfo;
  2340. CheckTVChain();
  2341. m_forcePositionMapSync = true;
  2342. m_inJumpToProgramPause = false;
  2343. Play();
  2344. ChangeSpeed();
  2345. // check that we aren't too close to the end of program.
  2346. // and if so set it to 10s from the end if completed recordings
  2347. // or 3s if live
  2348. long long duration = m_playerCtx->m_tvchain->GetLengthAtCurPos();
  2349. int maxpos = m_playerCtx->m_tvchain->HasNext() ? 10 : 3;
  2350. if (nextpos > (duration - maxpos))
  2351. {
  2352. nextpos = duration - maxpos;
  2353. if (nextpos < 0)
  2354. {
  2355. nextpos = 0;
  2356. }
  2357. }
  2358. else if (nextpos < 0)
  2359. {
  2360. // it's a relative position to the end
  2361. nextpos += duration;
  2362. }
  2363. // nextpos is the new position to use in seconds
  2364. nextpos = TranslatePositionMsToFrame(nextpos * 1000, true);
  2365. if (nextpos > 10)
  2366. DoJumpToFrame(nextpos, kInaccuracyNone);
  2367. m_playerCtx->SetPlayerChangingBuffers(false);
  2368. LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToProgram - end");
  2369. }
  2370. bool MythPlayer::StartPlaying(void)
  2371. {
  2372. if (OpenFile() < 0)
  2373. {
  2374. LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to open video file.");
  2375. return false;
  2376. }
  2377. m_framesPlayed = 0;
  2378. m_rewindTime = m_ffTime = 0;
  2379. m_nextPlaySpeed = m_audio.GetStretchFactor();
  2380. m_jumpChapter = 0;
  2381. m_commBreakMap.SkipCommercials(0);
  2382. m_bufferingCounter=0;
  2383. if (!InitVideo())
  2384. {
  2385. LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to initialize video.");
  2386. m_audio.DeleteOutput();
  2387. return false;
  2388. }
  2389. bool seek = m_bookmarkSeek > 30;
  2390. EventStart();
  2391. DecoderStart(true);
  2392. if (seek)
  2393. InitialSeek();
  2394. VideoStart();
  2395. m_playerThread->setPriority(QThread::TimeCriticalPriority);
  2396. #ifdef Q_OS_ANDROID
  2397. setpriority(PRIO_PROCESS, m_playerThreadId, -20);
  2398. #endif
  2399. ProcessCallbacks();
  2400. UnpauseDecoder();
  2401. return !IsErrored();
  2402. }
  2403. void MythPlayer::InitialSeek(void)
  2404. {
  2405. // TODO handle initial commskip and/or cutlist skip as well
  2406. if (m_bookmarkSeek > 30)
  2407. {
  2408. DoJumpToFrame(m_bookmarkSeek, kInaccuracyNone);
  2409. if (m_clearSavedPosition && !m_playerCtx->IsPIP())
  2410. SetBookmark(true);
  2411. }
  2412. }
  2413. void MythPlayer::StopPlaying()
  2414. {
  2415. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - begin"));
  2416. m_playerThread->setPriority(QThread::NormalPriority);
  2417. #ifdef Q_OS_ANDROID
  2418. setpriority(PRIO_PROCESS, m_playerThreadId, 0);
  2419. #endif
  2420. ProcessCallbacks();
  2421. DecoderEnd();
  2422. VideoEnd();
  2423. AudioEnd();
  2424. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - end"));
  2425. }
  2426. void MythPlayer::EventStart(void)
  2427. {
  2428. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  2429. {
  2430. if (m_playerCtx->m_playingInfo)
  2431. {
  2432. // When initial playback gets underway, we override the ProgramInfo
  2433. // flags such that future calls to GetBookmark() will consider only
  2434. // an actual bookmark and not progstart or lastplaypos information.
  2435. m_playerCtx->m_playingInfo->SetIgnoreBookmark(false);
  2436. m_playerCtx->m_playingInfo->SetIgnoreProgStart(true);
  2437. m_playerCtx->m_playingInfo->SetAllowLastPlayPos(false);
  2438. }
  2439. }
  2440. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  2441. m_commBreakMap.LoadMap(m_playerCtx, m_framesPlayed);
  2442. }
  2443. void MythPlayer::EventLoop(void)
  2444. {
  2445. // Handle decoder callbacks
  2446. ProcessCallbacks();
  2447. // Live TV program change
  2448. if (m_fileChanged)
  2449. FileChanged();
  2450. // recreate the osd if a reinit was triggered by another thread
  2451. if (m_reinitOsd)
  2452. ReinitOSD();
  2453. // reselect subtitle tracks if triggered by the decoder
  2454. if (m_enableCaptions)
  2455. SetCaptionsEnabled(true, false);
  2456. if (m_disableCaptions)
  2457. SetCaptionsEnabled(false, false);
  2458. // enable/disable forced subtitles if signalled by the decoder
  2459. if (m_enableForcedSubtitles)
  2460. DoEnableForcedSubtitles();
  2461. if (m_disableForcedSubtitles)
  2462. DoDisableForcedSubtitles();
  2463. // reset the scan (and hence deinterlacers) if triggered by the decoder
  2464. if (m_resetScan != kScan_Ignore)
  2465. SetScanType(m_resetScan);
  2466. // refresh the position map for an in-progress recording while editing
  2467. if (m_hasFullPositionMap && IsWatchingInprogress() && m_deleteMap.IsEditing())
  2468. {
  2469. if (m_editUpdateTimer.hasExpired(2000))
  2470. {
  2471. // N.B. the positionmap update and osd refresh are asynchronous
  2472. m_forcePositionMapSync = true;
  2473. m_osdLock.lock();
  2474. m_deleteMap.UpdateOSD(m_framesPlayed, m_videoFrameRate, m_osd);
  2475. m_osdLock.unlock();
  2476. m_editUpdateTimer.start();
  2477. }
  2478. }
  2479. // Refresh the programinfo in use status
  2480. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  2481. if (m_playerCtx->m_playingInfo)
  2482. m_playerCtx->m_playingInfo->UpdateInUseMark();
  2483. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  2484. // Disable timestretch if we are too close to the end of the buffer
  2485. if (m_ffrewSkip == 1 && (m_playSpeed > 1.0F) && IsNearEnd())
  2486. {
  2487. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near end, Slowing down playback.");
  2488. Play(1.0F, true, true);
  2489. }
  2490. if (m_isDummy && m_playerCtx->m_tvchain && m_playerCtx->m_tvchain->HasNext())
  2491. {
  2492. // Switch from the dummy recorder to the tuned program in livetv
  2493. m_playerCtx->m_tvchain->JumpToNext(true, 0);
  2494. JumpToProgram();
  2495. }
  2496. else if ((!m_allPaused || GetEof() != kEofStateNone) &&
  2497. m_playerCtx->m_tvchain &&
  2498. (m_decoder && !m_decoder->GetWaitForChange()))
  2499. {
  2500. // Switch to the next program in livetv
  2501. if (m_playerCtx->m_tvchain->NeedsToSwitch())
  2502. SwitchToProgram();
  2503. }
  2504. // Jump to the next program in livetv
  2505. if (m_playerCtx->m_tvchain && m_playerCtx->m_tvchain->NeedsToJump())
  2506. {
  2507. JumpToProgram();
  2508. }
  2509. // Change interactive stream if requested
  2510. { QMutexLocker locker(&m_streamLock);
  2511. if (!m_newStream.isEmpty())
  2512. {
  2513. QString stream = m_newStream;
  2514. m_newStream.clear();
  2515. locker.unlock();
  2516. JumpToStream(stream);
  2517. }}
  2518. // Disable fastforward if we are too close to the end of the buffer
  2519. if (m_ffrewSkip > 1 && (CalcMaxFFTime(100, false) < 100))
  2520. {
  2521. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near end, stopping fastforward.");
  2522. Play(1.0F, true, true);
  2523. }
  2524. // Disable rewind if we are too close to the beginning of the buffer
  2525. if (m_ffrewSkip < 0 && CalcRWTime(-m_ffrewSkip) >= 0 &&
  2526. (m_framesPlayed <= m_keyframeDist))
  2527. {
  2528. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near start, stopping rewind.");
  2529. float stretch = (m_ffrewSkip > 0) ? 1.0F : m_audio.GetStretchFactor();
  2530. Play(stretch, true, true);
  2531. }
  2532. // Check for error
  2533. if (IsErrored() || m_playerCtx->IsRecorderErrored())
  2534. {
  2535. LOG(VB_GENERAL, LOG_ERR, LOC +
  2536. "Unknown recorder error, exiting decoder");
  2537. if (!IsErrored())
  2538. SetErrored(tr("Irrecoverable recorder error"));
  2539. m_killDecoder = true;
  2540. return;
  2541. }
  2542. // Handle speed change
  2543. if (m_playSpeed != m_nextPlaySpeed &&
  2544. (!m_playerCtx->m_tvchain ||
  2545. (m_playerCtx->m_tvchain && !m_playerCtx->m_tvchain->NeedsToJump())))
  2546. {
  2547. ChangeSpeed();
  2548. return;
  2549. }
  2550. // Check if we got a communication error, and if so pause playback
  2551. if (m_playerCtx->m_buffer->GetCommsError())
  2552. {
  2553. Pause();
  2554. m_playerCtx->m_buffer->ResetCommsError();
  2555. }
  2556. // Handle end of file
  2557. EofState eof = GetEof();
  2558. if (HasReachedEof())
  2559. {
  2560. #ifdef USING_MHEG
  2561. if (m_interactiveTV && m_interactiveTV->StreamStarted(false))
  2562. {
  2563. Pause();
  2564. return;
  2565. }
  2566. #endif
  2567. if (m_playerCtx->m_tvchain && m_playerCtx->m_tvchain->HasNext())
  2568. {
  2569. LOG(VB_GENERAL, LOG_NOTICE, LOC + "LiveTV forcing JumpTo 1");
  2570. m_playerCtx->m_tvchain->JumpToNext(true, 0);
  2571. return;
  2572. }
  2573. bool videoDrained =
  2574. m_videoOutput && m_videoOutput->ValidVideoFrames() < 1;
  2575. bool audioDrained =
  2576. !m_audio.GetAudioOutput() ||
  2577. m_audio.IsPaused() ||
  2578. m_audio.GetAudioOutput()->GetAudioBufferedTime() < 100;
  2579. if (eof != kEofStateDelayed || (videoDrained && audioDrained))
  2580. {
  2581. if (eof == kEofStateDelayed)
  2582. {
  2583. LOG(VB_PLAYBACK, LOG_INFO,
  2584. QString("waiting for no video frames %1")
  2585. .arg(m_videoOutput->ValidVideoFrames()));
  2586. }
  2587. LOG(VB_PLAYBACK, LOG_INFO,
  2588. QString("HasReachedEof() at framesPlayed=%1 totalFrames=%2")
  2589. .arg(m_framesPlayed).arg(GetCurrentFrameCount()));
  2590. Pause();
  2591. SetPlaying(false);
  2592. return;
  2593. }
  2594. }
  2595. // Handle rewind
  2596. if (m_rewindTime > 0 && (m_ffrewSkip == 1 || m_ffrewSkip == 0))
  2597. {
  2598. m_rewindTime = CalcRWTime(m_rewindTime);
  2599. if (m_rewindTime > 0)
  2600. DoRewind(m_rewindTime, kInaccuracyDefault);
  2601. }
  2602. // Handle fast forward
  2603. if (m_ffTime > 0 && (m_ffrewSkip == 1 || m_ffrewSkip == 0))
  2604. {
  2605. m_ffTime = CalcMaxFFTime(m_ffTime);
  2606. if (m_ffTime > 0)
  2607. {
  2608. DoFastForward(m_ffTime, kInaccuracyDefault);
  2609. if (GetEof() != kEofStateNone)
  2610. return;
  2611. }
  2612. }
  2613. // Handle chapter jump
  2614. if (m_jumpChapter != 0)
  2615. DoJumpChapter(m_jumpChapter);
  2616. // Handle commercial skipping
  2617. if (m_commBreakMap.GetSkipCommercials() != 0 && (m_ffrewSkip == 1))
  2618. {
  2619. if (!m_commBreakMap.HasMap())
  2620. {
  2621. //: The commercials/adverts have not been flagged
  2622. SetOSDStatus(tr("Not Flagged"), kOSDTimeout_Med);
  2623. QString message = "COMMFLAG_REQUEST ";
  2624. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  2625. message += QString("%1").arg(m_playerCtx->m_playingInfo->GetChanID()) +
  2626. " " + m_playerCtx->m_playingInfo->MakeUniqueKey();
  2627. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  2628. gCoreContext->SendMessage(message);
  2629. }
  2630. else
  2631. {
  2632. QString msg;
  2633. uint64_t jumpto = 0;
  2634. uint64_t frameCount = GetCurrentFrameCount();
  2635. // XXX CommBreakMap should use duration map not m_videoFrameRate
  2636. bool jump = m_commBreakMap.DoSkipCommercials(jumpto, m_framesPlayed,
  2637. m_videoFrameRate,
  2638. frameCount, msg);
  2639. if (!msg.isEmpty())
  2640. SetOSDStatus(msg, kOSDTimeout_Med);
  2641. if (jump)
  2642. DoJumpToFrame(jumpto, kInaccuracyNone);
  2643. }
  2644. m_commBreakMap.SkipCommercials(0);
  2645. return;
  2646. }
  2647. // Handle automatic commercial skipping
  2648. uint64_t jumpto = 0;
  2649. if (m_deleteMap.IsEmpty() && (m_ffrewSkip == 1) &&
  2650. (kCommSkipOff != m_commBreakMap.GetAutoCommercialSkip()) &&
  2651. m_commBreakMap.HasMap())
  2652. {
  2653. QString msg;
  2654. uint64_t frameCount = GetCurrentFrameCount();
  2655. // XXX CommBreakMap should use duration map not m_videoFrameRate
  2656. bool jump = m_commBreakMap.AutoCommercialSkip(jumpto, m_framesPlayed,
  2657. m_videoFrameRate,
  2658. frameCount, msg);
  2659. if (!msg.isEmpty())
  2660. SetOSDStatus(msg, kOSDTimeout_Med);
  2661. if (jump)
  2662. DoJumpToFrame(jumpto, kInaccuracyNone);
  2663. }
  2664. // Handle cutlist skipping
  2665. if (!m_allPaused && (m_ffrewSkip == 1) &&
  2666. m_deleteMap.TrackerWantsToJump(m_framesPlayed, jumpto))
  2667. {
  2668. if (jumpto == m_totalFrames)
  2669. {
  2670. if (!(m_endExitPrompt == 1 && !m_playerCtx->IsPIP() &&
  2671. m_playerCtx->GetState() == kState_WatchingPreRecorded))
  2672. {
  2673. SetEof(kEofStateDelayed);
  2674. }
  2675. }
  2676. else
  2677. {
  2678. DoJumpToFrame(jumpto, kInaccuracyNone);
  2679. }
  2680. }
  2681. }
  2682. void MythPlayer::AudioEnd(void)
  2683. {
  2684. m_audio.DeleteOutput();
  2685. }
  2686. /*! \brief Convenience function to request and wait for a callback into the main thread.
  2687. *
  2688. * This is used by hardware decoders to ensure certain resources are created
  2689. * and destroyed in the UI (render) thread.
  2690. */
  2691. void MythPlayer::HandleDecoderCallback(const QString &Debug, DecoderCallback::Callback Function,
  2692. void *Opaque1, void *Opaque2)
  2693. {
  2694. if (!Function)
  2695. return;
  2696. m_decoderCallbackLock.lock();
  2697. QAtomicInt ready{0};
  2698. QWaitCondition wait;
  2699. LOG(VB_GENERAL, LOG_INFO, LOC + QString("Queuing callback for %1").arg(Debug));
  2700. m_decoderCallbacks.append(DecoderCallback(Debug, Function, &ready, &wait, Opaque1, Opaque2));
  2701. int count = 0;
  2702. while (!ready && !wait.wait(&m_decoderCallbackLock, 100) && (count += 100))
  2703. LOG(VB_GENERAL, LOG_WARNING, QString("Waited %1ms for %2").arg(count).arg(Debug));
  2704. m_decoderCallbackLock.unlock();
  2705. }
  2706. void MythPlayer::ProcessCallbacks(void)
  2707. {
  2708. m_decoderCallbackLock.lock();
  2709. for (auto *it = m_decoderCallbacks.begin(); it != m_decoderCallbacks.end(); ++it)
  2710. {
  2711. if (it->m_function)
  2712. {
  2713. LOG(VB_GENERAL, LOG_INFO, LOC + QString("Executing %1").arg(it->m_debug));
  2714. it->m_function(it->m_opaque1, it->m_opaque2, it->m_opaque3);
  2715. }
  2716. if (it->m_ready)
  2717. it->m_ready->ref();
  2718. }
  2719. m_decoderCallbacks.clear();
  2720. m_decoderCallbackLock.unlock();
  2721. }
  2722. bool MythPlayer::PauseDecoder(void)
  2723. {
  2724. m_decoderPauseLock.lock();
  2725. if (is_current_thread(m_decoderThread))
  2726. {
  2727. m_decoderPaused = true;
  2728. m_decoderThreadPause.wakeAll();
  2729. m_decoderPauseLock.unlock();
  2730. return m_decoderPaused;
  2731. }
  2732. int tries = 0;
  2733. m_pauseDecoder = true;
  2734. while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
  2735. !m_decoderThreadPause.wait(&m_decoderPauseLock, 100))
  2736. {
  2737. ProcessCallbacks();
  2738. LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to pause");
  2739. }
  2740. m_pauseDecoder = false;
  2741. m_decoderPauseLock.unlock();
  2742. return m_decoderPaused;
  2743. }
  2744. void MythPlayer::UnpauseDecoder(void)
  2745. {
  2746. m_decoderPauseLock.lock();
  2747. if (is_current_thread(m_decoderThread))
  2748. {
  2749. m_decoderPaused = false;
  2750. m_decoderThreadUnpause.wakeAll();
  2751. m_decoderPauseLock.unlock();
  2752. return;
  2753. }
  2754. if (!IsInStillFrame())
  2755. {
  2756. int tries = 0;
  2757. m_unpauseDecoder = true;
  2758. while (m_decoderThread && !m_killDecoder && (tries++ < 100) &&
  2759. !m_decoderThreadUnpause.wait(&m_decoderPauseLock, 100))
  2760. {
  2761. ProcessCallbacks();
  2762. LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to unpause");
  2763. }
  2764. m_unpauseDecoder = false;
  2765. }
  2766. m_decoderPauseLock.unlock();
  2767. }
  2768. void MythPlayer::DecoderStart(bool start_paused)
  2769. {
  2770. if (m_decoderThread)
  2771. {
  2772. if (m_decoderThread->isRunning())
  2773. {
  2774. LOG(VB_GENERAL, LOG_ERR, LOC + "Decoder thread already running");
  2775. }
  2776. delete m_decoderThread;
  2777. }
  2778. m_killDecoder = false;
  2779. m_decoderPaused = start_paused;
  2780. m_decoderThread = new DecoderThread(this, start_paused);
  2781. if (m_decoderThread)
  2782. m_decoderThread->start();
  2783. }
  2784. void MythPlayer::DecoderEnd(void)
  2785. {
  2786. PauseDecoder();
  2787. SetPlaying(false);
  2788. // Ensure any hardware frames are released (after pausing the decoder) to
  2789. // allow the decoder to exit cleanly
  2790. DiscardVideoFrames(true, true);
  2791. m_killDecoder = true;
  2792. int tries = 0;
  2793. while (m_decoderThread && !m_decoderThread->wait(100) && (tries++ < 50))
  2794. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  2795. "Waited 100ms for decoder loop to stop");
  2796. if (m_decoderThread && m_decoderThread->isRunning())
  2797. LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to stop decoder loop.");
  2798. else
  2799. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exited decoder loop.");
  2800. SetDecoder(nullptr);
  2801. }
  2802. void MythPlayer::DecoderPauseCheck(void)
  2803. {
  2804. if (is_current_thread(m_decoderThread))
  2805. {
  2806. if (m_pauseDecoder)
  2807. PauseDecoder();
  2808. if (m_unpauseDecoder)
  2809. UnpauseDecoder();
  2810. }
  2811. }
  2812. //// FIXME - move the eof ownership back into MythPlayer
  2813. EofState MythPlayer::GetEof(void) const
  2814. {
  2815. if (is_current_thread(m_playerThread))
  2816. return m_decoder ? m_decoder->GetEof() : kEofStateImmediate;
  2817. if (!m_decoderChangeLock.tryLock(50))
  2818. return kEofStateNone;
  2819. EofState eof = m_decoder ? m_decoder->GetEof() : kEofStateImmediate;
  2820. m_decoderChangeLock.unlock();
  2821. return eof;
  2822. }
  2823. void MythPlayer::SetEof(EofState eof)
  2824. {
  2825. if (is_current_thread(m_playerThread))
  2826. {
  2827. if (m_decoder)
  2828. m_decoder->SetEofState(eof);
  2829. return;
  2830. }
  2831. if (!m_decoderChangeLock.tryLock(50))
  2832. return;
  2833. if (m_decoder)
  2834. m_decoder->SetEofState(eof);
  2835. m_decoderChangeLock.unlock();
  2836. }
  2837. //// FIXME end
  2838. void MythPlayer::DecoderLoop(bool pause)
  2839. {
  2840. if (pause)
  2841. PauseDecoder();
  2842. while (!m_killDecoder && !IsErrored())
  2843. {
  2844. DecoderPauseCheck();
  2845. if (m_totalDecoderPause || m_inJumpToProgramPause)
  2846. {
  2847. usleep(1000);
  2848. continue;
  2849. }
  2850. if (m_forcePositionMapSync)
  2851. {
  2852. if (!m_decoderChangeLock.tryLock(1))
  2853. continue;
  2854. if (m_decoder)
  2855. {
  2856. m_forcePositionMapSync = false;
  2857. m_decoder->SyncPositionMap();
  2858. }
  2859. m_decoderChangeLock.unlock();
  2860. }
  2861. if (m_decoderSeek >= 0)
  2862. {
  2863. if (!m_decoderChangeLock.tryLock(1))
  2864. continue;
  2865. if (m_decoder)
  2866. {
  2867. m_decoderSeekLock.lock();
  2868. if (((uint64_t)m_decoderSeek < m_framesPlayed) && m_decoder)
  2869. m_decoder->DoRewind(m_decoderSeek);
  2870. else if (m_decoder)
  2871. m_decoder->DoFastForward(m_decoderSeek, !m_transcoding);
  2872. m_decoderSeek = -1;
  2873. m_decoderSeekLock.unlock();
  2874. }
  2875. m_decoderChangeLock.unlock();
  2876. }
  2877. bool obey_eof = (GetEof() != kEofStateNone) &&
  2878. !(m_playerCtx->m_tvchain && !m_allPaused);
  2879. if (m_isDummy || ((m_decoderPaused || m_ffrewSkip == 0 || obey_eof) &&
  2880. !m_decodeOneFrame))
  2881. {
  2882. usleep(1000);
  2883. continue;
  2884. }
  2885. DecodeType dt = m_deleteMap.IsEditing() || (m_audio.HasAudioOut() && m_normalSpeed) ?
  2886. kDecodeAV : kDecodeVideo;
  2887. DecoderGetFrame(dt);
  2888. m_decodeOneFrame = false;
  2889. }
  2890. // Clear any wait conditions
  2891. DecoderPauseCheck();
  2892. m_decoderSeek = -1;
  2893. }
  2894. bool MythPlayer::DecoderGetFrameFFREW(void)
  2895. {
  2896. if (!m_decoder)
  2897. return false;
  2898. if (m_ffrewSkip > 0)
  2899. {
  2900. long long delta = m_decoder->GetFramesRead() - m_framesPlayed;
  2901. long long real_skip = CalcMaxFFTime(m_ffrewSkip - m_ffrewAdjust + delta) - delta;
  2902. long long target_frame = m_decoder->GetFramesRead() + real_skip;
  2903. if (real_skip >= 0)
  2904. {
  2905. m_decoder->DoFastForward(target_frame, false);
  2906. }
  2907. long long seek_frame = m_decoder->GetFramesRead();
  2908. m_ffrewAdjust = seek_frame - target_frame;
  2909. }
  2910. else if (CalcRWTime(-m_ffrewSkip) >= 0)
  2911. {
  2912. DecoderGetFrameREW();
  2913. }
  2914. return DoGetFrame(m_deleteMap.IsEditing() ? kDecodeAV : kDecodeVideo);
  2915. }
  2916. bool MythPlayer::DecoderGetFrameREW(void)
  2917. {
  2918. long long cur_frame = m_decoder->GetFramesPlayed();
  2919. bool toBegin = -cur_frame > m_ffrewSkip + m_ffrewAdjust;
  2920. long long real_skip = (toBegin) ? -cur_frame : m_ffrewSkip + m_ffrewAdjust;
  2921. long long target_frame = cur_frame + real_skip;
  2922. bool ret = m_decoder->DoRewind(target_frame, false);
  2923. long long seek_frame = m_decoder->GetFramesPlayed();
  2924. m_ffrewAdjust = target_frame - seek_frame;
  2925. return ret;
  2926. }
  2927. bool MythPlayer::DecoderGetFrame(DecodeType decodetype, bool unsafe)
  2928. {
  2929. bool ret = false;
  2930. if (!m_videoOutput)
  2931. return false;
  2932. // Wait for frames to be available for decoding onto
  2933. int tries = 0;
  2934. while (!unsafe &&
  2935. (!m_videoOutput->EnoughFreeFrames() || GetAudio()->IsBufferAlmostFull()) )
  2936. {
  2937. if (m_killDecoder || m_pauseDecoder)
  2938. return false;
  2939. if (++tries > 10)
  2940. {
  2941. if (++m_videobufRetries >= 2000)
  2942. {
  2943. LOG(VB_GENERAL, LOG_ERR, LOC +
  2944. "Decoder timed out waiting for free video buffers.");
  2945. // We've tried for 20 seconds now, give up so that we don't
  2946. // get stuck permanently in this state
  2947. SetErrored("Decoder timed out waiting for free video buffers.");
  2948. }
  2949. return false;
  2950. }
  2951. usleep(1000);
  2952. }
  2953. m_videobufRetries = 0;
  2954. if (!m_decoderChangeLock.tryLock(5))
  2955. return false;
  2956. if (m_killDecoder || !m_decoder || m_pauseDecoder || IsErrored())
  2957. {
  2958. m_decoderChangeLock.unlock();
  2959. return false;
  2960. }
  2961. if (m_ffrewSkip == 1 || m_decodeOneFrame)
  2962. ret = DoGetFrame(decodetype);
  2963. else if (m_ffrewSkip != 0)
  2964. ret = DecoderGetFrameFFREW();
  2965. m_decoderChangeLock.unlock();
  2966. return ret;
  2967. }
  2968. /*! \brief Get one frame from the decoder.
  2969. *
  2970. * Certain decoders operate asynchronously and will return EAGAIN if a
  2971. * video frame is not yet ready. We handle the retries here in MythPlayer
  2972. * so that we can abort retries if we need to pause or stop the decoder.
  2973. *
  2974. * This is most relevant for MediaCodec decoding when using direct rendering
  2975. * as there are a limited number of decoder output buffers that are retained by
  2976. * the VideoOutput classes (VideoOutput and VideoBuffers) until they have been
  2977. * used.
  2978. *
  2979. * \note The caller must hold m_decoderChangeLock.
  2980. */
  2981. bool MythPlayer::DoGetFrame(DecodeType Type)
  2982. {
  2983. bool ret = false;
  2984. QElapsedTimer timeout;
  2985. timeout.start();
  2986. bool retry = true;
  2987. // retry for a maximum of 5 seconds
  2988. while (retry && !m_pauseDecoder && !m_killDecoder && !timeout.hasExpired(5000))
  2989. {
  2990. retry = false;
  2991. ret = m_decoder->GetFrame(Type, retry);
  2992. if (retry)
  2993. {
  2994. m_decoderChangeLock.unlock();
  2995. QThread::usleep(10000);
  2996. m_decoderChangeLock.lock();
  2997. }
  2998. }
  2999. if (timeout.hasExpired(5000))
  3000. return false;
  3001. return ret;
  3002. }
  3003. void MythPlayer::SetTranscoding(bool value)
  3004. {
  3005. m_transcoding = value;
  3006. if (m_decoder)
  3007. m_decoder->SetTranscoding(value);
  3008. }
  3009. bool MythPlayer::AddPIPPlayer(MythPlayer *pip, PIPLocation loc)
  3010. {
  3011. if (!is_current_thread(m_playerThread))
  3012. {
  3013. LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot add PiP from another thread");
  3014. return false;
  3015. }
  3016. if (m_pipPlayers.contains(pip))
  3017. {
  3018. LOG(VB_GENERAL, LOG_ERR, LOC + "PiPMap already contains PiP.");
  3019. return false;
  3020. }
  3021. QList<PIPLocation> locs = m_pipPlayers.values();
  3022. if (locs.contains(loc))
  3023. {
  3024. LOG(VB_GENERAL, LOG_ERR, LOC +"Already have a PiP at that location.");
  3025. return false;
  3026. }
  3027. m_pipPlayers.insert(pip, loc);
  3028. return true;
  3029. }
  3030. bool MythPlayer::RemovePIPPlayer(MythPlayer *pip)
  3031. {
  3032. if (!is_current_thread(m_playerThread))
  3033. return false;
  3034. if (!m_pipPlayers.contains(pip))
  3035. return false;
  3036. m_pipPlayers.remove(pip);
  3037. if (m_videoOutput)
  3038. m_videoOutput->RemovePIP(pip);
  3039. return true;
  3040. }
  3041. PIPLocation MythPlayer::GetNextPIPLocation(void) const
  3042. {
  3043. if (!is_current_thread(m_playerThread))
  3044. return kPIP_END;
  3045. if (m_pipPlayers.isEmpty())
  3046. return m_pipDefaultLoc;
  3047. // order of preference, could be stored in db if we want it configurable
  3048. PIPLocation ols[] =
  3049. { kPIPTopLeft, kPIPTopRight, kPIPBottomLeft, kPIPBottomRight };
  3050. for (auto & ol : ols)
  3051. {
  3052. PIPMap::const_iterator it = m_pipPlayers.begin();
  3053. for (; it != m_pipPlayers.end() && (*it != ol); ++it);
  3054. if (it == m_pipPlayers.end())
  3055. return ol;
  3056. }
  3057. return kPIP_END;
  3058. }
  3059. int64_t MythPlayer::AdjustAudioTimecodeOffset(int64_t v, int newsync)
  3060. {
  3061. if ((newsync >= -1000) && (newsync <= 1000))
  3062. m_tcWrap[TC_AUDIO] = newsync;
  3063. else
  3064. m_tcWrap[TC_AUDIO] += v;
  3065. return m_tcWrap[TC_AUDIO];
  3066. }
  3067. void MythPlayer::WrapTimecode(int64_t &timecode, TCTypes tc_type)
  3068. {
  3069. timecode += m_tcWrap[tc_type];
  3070. }
  3071. bool MythPlayer::PrepareAudioSample(int64_t &timecode)
  3072. {
  3073. WrapTimecode(timecode, TC_AUDIO);
  3074. return false;
  3075. }
  3076. /**
  3077. * \brief Determines if the recording should be considered watched
  3078. *
  3079. * By comparing the number of framesPlayed to the total number of
  3080. * frames in the video minus an offset (14%) we determine if the
  3081. * recording is likely to have been watched to the end, ignoring
  3082. * end credits and trailing adverts.
  3083. *
  3084. * PlaybackInfo::SetWatchedFlag is then called with the argument TRUE
  3085. * or FALSE accordingly.
  3086. *
  3087. * \param forceWatched Forces a recording watched ignoring the amount
  3088. * actually played (Optional)
  3089. */
  3090. void MythPlayer::SetWatched(bool forceWatched)
  3091. {
  3092. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3093. if (!m_playerCtx->m_playingInfo)
  3094. {
  3095. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3096. return;
  3097. }
  3098. uint64_t numFrames = GetCurrentFrameCount();
  3099. // For recordings we want to ignore the post-roll and account for
  3100. // in-progress recordings where totalFrames doesn't represent
  3101. // the full length of the recording. For videos we can only rely on
  3102. // totalFrames as duration metadata can be wrong
  3103. if (m_playerCtx->m_playingInfo->IsRecording() &&
  3104. m_playerCtx->m_playingInfo->QueryTranscodeStatus() !=
  3105. TRANSCODING_COMPLETE)
  3106. {
  3107. // If the recording is stopped early we need to use the recording end
  3108. // time, not the programme end time
  3109. #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
  3110. uint endtime;
  3111. if (m_playerCtx->m_playingInfo->GetRecordingEndTime().toTime_t() <
  3112. m_playerCtx->m_playingInfo->GetScheduledEndTime().toTime_t())
  3113. {
  3114. endtime = m_playerCtx->m_playingInfo->GetRecordingEndTime().toTime_t();
  3115. }
  3116. else
  3117. {
  3118. endtime = m_playerCtx->m_playingInfo->GetScheduledEndTime().toTime_t();
  3119. }
  3120. numFrames = (long long)
  3121. ((endtime -
  3122. m_playerCtx->m_playingInfo->GetRecordingStartTime().toTime_t()) *
  3123. m_videoFrameRate);
  3124. #else
  3125. ProgramInfo *pi = m_playerCtx->m_playingInfo;
  3126. qint64 starttime = pi->GetRecordingStartTime().toSecsSinceEpoch();
  3127. qint64 endactual = pi->GetRecordingEndTime().toSecsSinceEpoch();
  3128. qint64 endsched = pi->GetScheduledEndTime().toSecsSinceEpoch();
  3129. qint64 endtime = min(endactual, endsched);
  3130. numFrames = (long long) ((endtime - starttime) * m_videoFrameRate);
  3131. #endif
  3132. }
  3133. int offset = (int) round(0.14 * (numFrames / m_videoFrameRate));
  3134. if (offset < 240)
  3135. offset = 240; // 4 Minutes Min
  3136. else if (offset > 720)
  3137. offset = 720; // 12 Minutes Max
  3138. if (forceWatched || m_framesPlayed > numFrames - (offset * m_videoFrameRate))
  3139. {
  3140. m_playerCtx->m_playingInfo->SaveWatched(true);
  3141. LOG(VB_GENERAL, LOG_INFO, LOC +
  3142. QString("Marking recording as watched using offset %1 minutes")
  3143. .arg(offset/60));
  3144. }
  3145. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3146. }
  3147. void MythPlayer::SetBookmark(bool clear)
  3148. {
  3149. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3150. if (m_playerCtx->m_playingInfo)
  3151. m_playerCtx->m_playingInfo->SaveBookmark(clear ? 0 : m_framesPlayed);
  3152. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3153. }
  3154. uint64_t MythPlayer::GetBookmark(void)
  3155. {
  3156. uint64_t bookmark = 0;
  3157. if (gCoreContext->IsDatabaseIgnored() ||
  3158. (m_playerCtx->m_buffer && !m_playerCtx->m_buffer->IsBookmarkAllowed()))
  3159. bookmark = 0;
  3160. else
  3161. {
  3162. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3163. if (const ProgramInfo *pi = m_playerCtx->m_playingInfo)
  3164. {
  3165. bookmark = pi->QueryBookmark();
  3166. // Disable progstart if the program has a cutlist.
  3167. if (bookmark == 0 && !pi->HasCutlist())
  3168. bookmark = pi->QueryProgStart();
  3169. if (bookmark == 0)
  3170. bookmark = pi->QueryLastPlayPos();
  3171. }
  3172. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3173. }
  3174. return bookmark;
  3175. }
  3176. bool MythPlayer::UpdateFFRewSkip(void)
  3177. {
  3178. bool skip_changed = false;
  3179. float temp_speed = (m_playSpeed == 0.0F) ?
  3180. m_audio.GetStretchFactor() : m_playSpeed;
  3181. if (m_playSpeed >= 0.0F && m_playSpeed <= 3.0F)
  3182. {
  3183. skip_changed = (m_ffrewSkip != 1);
  3184. if (m_decoder)
  3185. m_fpsMultiplier = m_decoder->GetfpsMultiplier();
  3186. m_frameInterval = (int) (1000000.0 / m_videoFrameRate / static_cast<double>(temp_speed))
  3187. / m_fpsMultiplier;
  3188. m_ffrewSkip = static_cast<int>(m_playSpeed != 0.0F);
  3189. }
  3190. else
  3191. {
  3192. skip_changed = true;
  3193. m_frameInterval = 200000;
  3194. m_frameInterval = (fabs(m_playSpeed) >= 3.0F) ? 133466 : m_frameInterval;
  3195. m_frameInterval = (fabs(m_playSpeed) >= 5.0F) ? 133466 : m_frameInterval;
  3196. m_frameInterval = (fabs(m_playSpeed) >= 8.0F) ? 250250 : m_frameInterval;
  3197. m_frameInterval = (fabs(m_playSpeed) >= 10.0F) ? 133466 : m_frameInterval;
  3198. m_frameInterval = (fabs(m_playSpeed) >= 16.0F) ? 187687 : m_frameInterval;
  3199. m_frameInterval = (fabs(m_playSpeed) >= 20.0F) ? 150150 : m_frameInterval;
  3200. m_frameInterval = (fabs(m_playSpeed) >= 30.0F) ? 133466 : m_frameInterval;
  3201. m_frameInterval = (fabs(m_playSpeed) >= 60.0F) ? 133466 : m_frameInterval;
  3202. m_frameInterval = (fabs(m_playSpeed) >= 120.0F) ? 133466 : m_frameInterval;
  3203. m_frameInterval = (fabs(m_playSpeed) >= 180.0F) ? 133466 : m_frameInterval;
  3204. float ffw_fps = fabs(static_cast<double>(m_playSpeed)) * m_videoFrameRate;
  3205. float dis_fps = 1000000.0F / m_frameInterval;
  3206. m_ffrewSkip = (int)ceil(ffw_fps / dis_fps);
  3207. m_ffrewSkip = m_playSpeed < 0.0F ? -m_ffrewSkip : m_ffrewSkip;
  3208. m_ffrewAdjust = 0;
  3209. }
  3210. return skip_changed;
  3211. }
  3212. void MythPlayer::ChangeSpeed(void)
  3213. {
  3214. float last_speed = m_playSpeed;
  3215. m_playSpeed = m_nextPlaySpeed;
  3216. m_normalSpeed = m_nextNormalSpeed;
  3217. m_rtcBase = 0;
  3218. bool skip_changed = UpdateFFRewSkip();
  3219. if (skip_changed && m_videoOutput)
  3220. {
  3221. m_videoOutput->SetPrebuffering(m_ffrewSkip == 1);
  3222. if (m_playSpeed != 0.0F && !(last_speed == 0.0F && m_ffrewSkip == 1))
  3223. DoJumpToFrame(m_framesPlayed + m_ffTime - m_rewindTime, kInaccuracyFull);
  3224. }
  3225. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Play speed: " +
  3226. QString("rate: %1 speed: %2 skip: %3 => new interval %4")
  3227. .arg(m_videoFrameRate).arg(static_cast<double>(m_playSpeed))
  3228. .arg(m_ffrewSkip).arg(m_frameInterval));
  3229. if (m_videoOutput)
  3230. m_videoOutput->SetVideoFrameRate(static_cast<float>(m_videoFrameRate));
  3231. // ensure we re-check double rate support following a speed change
  3232. m_scanInitialized = false;
  3233. m_scanLocked = false;
  3234. if (m_normalSpeed && m_audio.HasAudioOut())
  3235. {
  3236. m_audio.SetStretchFactor(m_playSpeed);
  3237. syncWithAudioStretch();
  3238. }
  3239. }
  3240. bool MythPlayer::DoRewind(uint64_t frames, double inaccuracy)
  3241. {
  3242. if (m_playerCtx->m_buffer && !m_playerCtx->m_buffer->IsSeekingAllowed())
  3243. return false;
  3244. uint64_t number = frames + 1;
  3245. uint64_t desiredFrame = (m_framesPlayed > number) ? m_framesPlayed - number : 0;
  3246. m_limitKeyRepeat = false;
  3247. if (desiredFrame < m_videoFrameRate)
  3248. m_limitKeyRepeat = true;
  3249. uint64_t seeksnap_wanted = UINT64_MAX;
  3250. if (inaccuracy != kInaccuracyFull)
  3251. seeksnap_wanted = frames * inaccuracy;
  3252. ClearBeforeSeek(frames);
  3253. WaitForSeek(desiredFrame, seeksnap_wanted);
  3254. m_rewindTime = 0;
  3255. ClearAfterSeek();
  3256. return true;
  3257. }
  3258. bool MythPlayer::DoRewindSecs(float secs, double inaccuracy, bool use_cutlist)
  3259. {
  3260. float current = ComputeSecs(m_framesPlayed, use_cutlist);
  3261. float target = current - secs;
  3262. if (target < 0)
  3263. target = 0;
  3264. uint64_t targetFrame = FindFrame(target, use_cutlist);
  3265. return DoRewind(m_framesPlayed - targetFrame, inaccuracy);
  3266. }
  3267. /**
  3268. * CalcRWTime(rw): rewind rw frames back.
  3269. * Handle livetv transitions if necessary
  3270. *
  3271. */
  3272. long long MythPlayer::CalcRWTime(long long rw) const
  3273. {
  3274. bool hasliveprev = (m_liveTV && m_playerCtx->m_tvchain &&
  3275. m_playerCtx->m_tvchain->HasPrev());
  3276. if (!hasliveprev || ((int64_t)m_framesPlayed >= rw))
  3277. {
  3278. return rw;
  3279. }
  3280. m_playerCtx->m_tvchain->JumpToNext(false, ((int64_t)m_framesPlayed - rw) / m_videoFrameRate);
  3281. return -1;
  3282. }
  3283. /**
  3284. * CalcMaxFFTime(ffframes): forward ffframes forward.
  3285. * Handle livetv transitions if necessay
  3286. */
  3287. long long MythPlayer::CalcMaxFFTime(long long ffframes, bool setjump) const
  3288. {
  3289. float maxtime = 1.0;
  3290. bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
  3291. !m_playerCtx->m_tvchain->HasNext());
  3292. if (m_liveTV || IsWatchingInprogress())
  3293. maxtime = 3.0;
  3294. long long ret = ffframes;
  3295. float ff = ComputeSecs(ffframes, true);
  3296. float secsPlayed = ComputeSecs(m_framesPlayed, true);
  3297. float secsWritten = ComputeSecs(m_totalFrames, true);
  3298. m_limitKeyRepeat = false;
  3299. if (m_liveTV && !islivetvcur && m_playerCtx->m_tvchain)
  3300. {
  3301. // recording has completed, totalFrames will always be up to date
  3302. if ((ffframes + m_framesPlayed > m_totalFrames) && setjump)
  3303. {
  3304. ret = -1;
  3305. // Number of frames to be skipped is from the end of the current segment
  3306. m_playerCtx->m_tvchain->JumpToNext(true, ((int64_t)m_totalFrames - (int64_t)m_framesPlayed - ffframes) / m_videoFrameRate);
  3307. }
  3308. }
  3309. else if (islivetvcur || IsWatchingInprogress())
  3310. {
  3311. if ((ff + secsPlayed) > secsWritten)
  3312. {
  3313. // If we attempt to seek past the last known duration,
  3314. // check for up to date data
  3315. long long framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
  3316. secsWritten = ComputeSecs(framesWritten, true);
  3317. }
  3318. float behind = secsWritten - secsPlayed;
  3319. if (behind < maxtime) // if we're close, do nothing
  3320. ret = 0;
  3321. else if (behind - ff <= maxtime)
  3322. ret = TranslatePositionMsToFrame(1000 * (secsWritten - maxtime),
  3323. true) - m_framesPlayed;
  3324. if (behind < maxtime * 3)
  3325. m_limitKeyRepeat = true;
  3326. }
  3327. else if (IsPaused())
  3328. {
  3329. uint64_t lastFrame =
  3330. m_deleteMap.IsEmpty() ? m_totalFrames : m_deleteMap.GetLastFrame();
  3331. if (m_framesPlayed + ffframes >= lastFrame)
  3332. ret = lastFrame - 1 - m_framesPlayed;
  3333. }
  3334. else
  3335. {
  3336. float secsMax = secsWritten - 2.F * maxtime;
  3337. if (secsMax <= 0.F)
  3338. ret = 0;
  3339. else if (secsMax < secsPlayed + ff)
  3340. ret = TranslatePositionMsToFrame(1000 * secsMax, true)
  3341. - m_framesPlayed;
  3342. }
  3343. return ret;
  3344. }
  3345. /** \fn MythPlayer::IsReallyNearEnd(void) const
  3346. * \brief Returns true iff really near end of recording.
  3347. *
  3348. * This is used by SwitchToProgram() to determine if we are so
  3349. * close to the end that we need to switch to the next program.
  3350. */
  3351. bool MythPlayer::IsReallyNearEnd(void) const
  3352. {
  3353. if (!m_videoOutput || !m_decoder)
  3354. return false;
  3355. return m_playerCtx->m_buffer->IsNearEnd(
  3356. m_decoder->GetFPS(), m_videoOutput->ValidVideoFrames());
  3357. }
  3358. /** \brief Returns true iff near end of recording.
  3359. */
  3360. bool MythPlayer::IsNearEnd(void)
  3361. {
  3362. if (!m_playerCtx)
  3363. return false;
  3364. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3365. if (!m_playerCtx->m_playingInfo || m_playerCtx->m_playingInfo->IsVideo() ||
  3366. !m_decoder)
  3367. {
  3368. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3369. return false;
  3370. }
  3371. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3372. auto margin = (long long)(m_videoFrameRate * 2);
  3373. margin = (long long) (margin * m_audio.GetStretchFactor());
  3374. bool watchingTV = IsWatchingInprogress();
  3375. uint64_t framesRead = m_framesPlayed;
  3376. uint64_t framesLeft = 0;
  3377. if (!m_playerCtx->IsPIP() &&
  3378. m_playerCtx->GetState() == kState_WatchingPreRecorded)
  3379. {
  3380. if (framesRead >= m_deleteMap.GetLastFrame())
  3381. return true;
  3382. uint64_t frameCount = GetCurrentFrameCount();
  3383. framesLeft = (frameCount > framesRead) ? frameCount - framesRead : 0;
  3384. return (framesLeft < (uint64_t)margin);
  3385. }
  3386. if (!m_liveTV && !watchingTV)
  3387. return false;
  3388. if (m_liveTV && m_playerCtx->m_tvchain && m_playerCtx->m_tvchain->HasNext())
  3389. return false;
  3390. if (m_playerCtx->m_recorder)
  3391. {
  3392. framesLeft =
  3393. m_playerCtx->m_recorder->GetCachedFramesWritten() - framesRead;
  3394. // if it looks like we are near end, get an updated GetFramesWritten()
  3395. if (framesLeft < (uint64_t)margin)
  3396. framesLeft = m_playerCtx->m_recorder->GetFramesWritten() - framesRead;
  3397. }
  3398. return (framesLeft < (uint64_t)margin);
  3399. }
  3400. bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
  3401. {
  3402. if (m_playerCtx->m_buffer && !m_playerCtx->m_buffer->IsSeekingAllowed())
  3403. return false;
  3404. uint64_t number = (frames ? frames - 1 : 0);
  3405. uint64_t desiredFrame = m_framesPlayed + number;
  3406. if (!m_deleteMap.IsEditing() && IsInDelete(desiredFrame))
  3407. {
  3408. uint64_t endcheck = m_deleteMap.GetLastFrame();
  3409. if (desiredFrame > endcheck)
  3410. desiredFrame = endcheck;
  3411. }
  3412. uint64_t seeksnap_wanted = UINT64_MAX;
  3413. if (inaccuracy != kInaccuracyFull)
  3414. seeksnap_wanted = frames * inaccuracy;
  3415. ClearBeforeSeek(frames);
  3416. WaitForSeek(desiredFrame, seeksnap_wanted);
  3417. m_ffTime = 0;
  3418. ClearAfterSeek(false);
  3419. return true;
  3420. }
  3421. bool MythPlayer::DoFastForwardSecs(float secs, double inaccuracy,
  3422. bool use_cutlist)
  3423. {
  3424. float current = ComputeSecs(m_framesPlayed, use_cutlist);
  3425. float target = current + secs;
  3426. uint64_t targetFrame = FindFrame(target, use_cutlist);
  3427. return DoFastForward(targetFrame - m_framesPlayed, inaccuracy);
  3428. }
  3429. void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
  3430. {
  3431. if (frame > m_framesPlayed)
  3432. DoFastForward(frame - m_framesPlayed, inaccuracy);
  3433. else if (frame <= m_framesPlayed)
  3434. DoRewind(m_framesPlayed - frame, inaccuracy);
  3435. }
  3436. void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
  3437. {
  3438. if (!m_decoder)
  3439. return;
  3440. SetEof(kEofStateNone);
  3441. m_decoder->SetSeekSnap(seeksnap_wanted);
  3442. bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
  3443. !m_playerCtx->m_tvchain->HasNext());
  3444. uint64_t max = GetCurrentFrameCount();
  3445. if (islivetvcur || IsWatchingInprogress())
  3446. {
  3447. max = (uint64_t)m_playerCtx->m_recorder->GetFramesWritten();
  3448. }
  3449. if (frame >= max)
  3450. frame = max - 1;
  3451. m_decoderSeekLock.lock();
  3452. m_decoderSeek = frame;
  3453. m_decoderSeekLock.unlock();
  3454. int count = 0;
  3455. bool need_clear = false;
  3456. while (m_decoderSeek >= 0)
  3457. {
  3458. // Waiting blocks the main UI thread but the decoder may
  3459. // have initiated a callback into the UI thread to create
  3460. // certain resources. Ensure the callback is processed.
  3461. // Ideally MythPlayer should be fully event driven and these
  3462. // calls wouldn't be necessary.
  3463. ProcessCallbacks();
  3464. usleep(50 * 1000);
  3465. // provide some on screen feedback if seeking is slow
  3466. count++;
  3467. if (!(count % 3) && !m_hasFullPositionMap)
  3468. {
  3469. int num = count % 3;
  3470. SetOSDMessage(tr("Searching") + QString().fill('.', num),
  3471. kOSDTimeout_Short);
  3472. DisplayPauseFrame();
  3473. need_clear = true;
  3474. }
  3475. }
  3476. if (need_clear)
  3477. {
  3478. m_osdLock.lock();
  3479. if (m_osd)
  3480. m_osd->HideWindow("osd_message");
  3481. m_osdLock.unlock();
  3482. }
  3483. }
  3484. /** \fn MythPlayer::ClearAfterSeek(bool)
  3485. * \brief This is to support seeking...
  3486. *
  3487. * This resets the output classes and discards all
  3488. * frames no longer being used by the decoder class.
  3489. *
  3490. * Note: caller should not hold any locks
  3491. *
  3492. * \param clearvideobuffers This clears the videooutput buffers as well,
  3493. * this is only safe if no old frames are
  3494. * required to continue decoding.
  3495. */
  3496. void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
  3497. {
  3498. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
  3499. .arg(clearvideobuffers));
  3500. if (clearvideobuffers && m_videoOutput)
  3501. m_videoOutput->ClearAfterSeek();
  3502. int64_t savedTC = m_tcWrap[TC_AUDIO];
  3503. for (int j = 0; j < TCTYPESMAX; j++)
  3504. m_tcWrap[j] = m_tcLastVal[j] = 0;
  3505. m_tcWrap[TC_AUDIO] = savedTC;
  3506. m_audio.Reset();
  3507. // Reenable (or re-disable) subtitles, which ultimately does
  3508. // nothing except to call ResetCaptions() to erase any captions
  3509. // currently on-screen. The key is that the erasing is done in
  3510. // the UI thread, not the decoder thread.
  3511. EnableSubtitles(m_textDesired);
  3512. m_deleteMap.TrackerReset(m_framesPlayed);
  3513. m_commBreakMap.SetTracker(m_framesPlayed);
  3514. m_commBreakMap.ResetLastSkip();
  3515. m_needNewPauseFrame = true;
  3516. ResetAVSync();
  3517. }
  3518. /*! \brief Discard video frames prior to seeking
  3519. * \note This is only used for MediaCodec surface rendering where the decoder will stall
  3520. * waiting for buffers if we do not free those buffers first. This is currently
  3521. * only an issue for recordings and livetv as the decoder is not paused before seeking when
  3522. * using a position map.
  3523. * \note m_watchingRecording does not appear to be accurate - so is currently ignored.
  3524. */
  3525. // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
  3526. void MythPlayer::ClearBeforeSeek(uint64_t Frames)
  3527. {
  3528. #ifdef USING_MEDIACODEC
  3529. LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("ClearBeforeSeek: decoder %1 frames %2 recording %3 livetv %4")
  3530. .arg(m_codecName).arg(Frames).arg(m_watchingRecording).arg(m_liveTV));
  3531. if ((Frames < 2) || !m_videoOutput /*|| !(m_liveTV || m_watchingRecording)*/)
  3532. return;
  3533. m_decoderChangeLock.lock();
  3534. MythCodecID codec = m_decoder ? m_decoder->GetVideoCodecID() : kCodec_NONE;
  3535. m_decoderChangeLock.unlock();
  3536. if (codec_is_mediacodec(codec))
  3537. m_videoOutput->DiscardFrames(true, true);
  3538. #else
  3539. Q_UNUSED(Frames);
  3540. #endif
  3541. }
  3542. void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget, PlayerContext *ctx)
  3543. {
  3544. m_deleteMap.SetPlayerContext(ctx);
  3545. m_tv = tv;
  3546. m_parentWidget = widget;
  3547. m_playerCtx = ctx;
  3548. m_liveTV = ctx->m_tvchain;
  3549. }
  3550. bool MythPlayer::EnableEdit(void)
  3551. {
  3552. m_deleteMap.SetEditing(false);
  3553. if (!m_hasFullPositionMap)
  3554. {
  3555. LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot edit - no full position map");
  3556. SetOSDStatus(tr("No Seektable"), kOSDTimeout_Med);
  3557. return false;
  3558. }
  3559. if (m_deleteMap.IsFileEditing())
  3560. return false;
  3561. QMutexLocker locker(&m_osdLock);
  3562. if (!m_osd)
  3563. return false;
  3564. m_audiograph.SetPainter(m_videoOutput->GetOSDPainter());
  3565. int sample_rate = GetAudio()->GetSampleRate();
  3566. m_audiograph.SetSampleRate(sample_rate);
  3567. m_audiograph.SetSampleCount((unsigned)(sample_rate / m_videoFrameRate));
  3568. GetAudio()->addVisual(&m_audiograph);
  3569. m_savedAudioTimecodeOffset = m_tcWrap[TC_AUDIO];
  3570. m_tcWrap[TC_AUDIO] = 0;
  3571. m_speedBeforeEdit = m_playSpeed;
  3572. m_pausedBeforeEdit = Pause();
  3573. m_deleteMap.SetEditing(true);
  3574. m_osd->DialogQuit();
  3575. ResetCaptions();
  3576. m_osd->HideAll();
  3577. bool loadedAutoSave = m_deleteMap.LoadAutoSaveMap();
  3578. if (loadedAutoSave)
  3579. {
  3580. SetOSDMessage(tr("Using previously auto-saved cuts"),
  3581. kOSDTimeout_Short);
  3582. }
  3583. m_deleteMap.UpdateSeekAmount(0);
  3584. m_deleteMap.UpdateOSD(m_framesPlayed, m_videoFrameRate, m_osd);
  3585. m_deleteMap.SetFileEditing(true);
  3586. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3587. if (m_playerCtx->m_playingInfo)
  3588. m_playerCtx->m_playingInfo->SaveEditing(true);
  3589. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3590. m_editUpdateTimer.start();
  3591. return m_deleteMap.IsEditing();
  3592. }
  3593. /** \fn MythPlayer::DisableEdit(int)
  3594. * \brief Leave cutlist edit mode, saving work in 1 of 3 ways.
  3595. *
  3596. * \param howToSave If 1, save all changes. If 0, discard all
  3597. * changes. If -1, do not explicitly save changes but leave
  3598. * auto-save information intact in the database.
  3599. */
  3600. void MythPlayer::DisableEdit(int howToSave)
  3601. {
  3602. QMutexLocker locker(&m_osdLock);
  3603. if (!m_osd)
  3604. return;
  3605. m_deleteMap.SetEditing(false, m_osd);
  3606. if (howToSave == 0)
  3607. m_deleteMap.LoadMap();
  3608. // Unconditionally save to remove temporary marks from the DB.
  3609. if (howToSave >= 0)
  3610. m_deleteMap.SaveMap();
  3611. m_deleteMap.TrackerReset(m_framesPlayed);
  3612. m_deleteMap.SetFileEditing(false);
  3613. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  3614. if (m_playerCtx->m_playingInfo)
  3615. m_playerCtx->m_playingInfo->SaveEditing(false);
  3616. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  3617. GetAudio()->removeVisual(&m_audiograph);
  3618. m_audiograph.Reset();
  3619. m_tcWrap[TC_AUDIO] = m_savedAudioTimecodeOffset;
  3620. m_savedAudioTimecodeOffset = 0;
  3621. if (!m_pausedBeforeEdit)
  3622. Play(m_speedBeforeEdit);
  3623. else
  3624. SetOSDStatus(tr("Paused"), kOSDTimeout_None);
  3625. }
  3626. bool MythPlayer::HandleProgramEditorActions(QStringList &actions)
  3627. {
  3628. bool handled = false;
  3629. bool refresh = true;
  3630. long long frame = GetFramesPlayed();
  3631. for (int i = 0; i < actions.size() && !handled; i++)
  3632. {
  3633. QString action = actions[i];
  3634. handled = true;
  3635. float seekamount = m_deleteMap.GetSeekAmount();
  3636. if (action == ACTION_LEFT)
  3637. {
  3638. if (seekamount == 0) // 1 frame
  3639. DoRewind(1, kInaccuracyNone);
  3640. else if (seekamount > 0)
  3641. {
  3642. // Use fully-accurate seeks for less than 1 second.
  3643. DoRewindSecs(seekamount, seekamount < 1.0F ? kInaccuracyNone :
  3644. kInaccuracyEditor, false);
  3645. }
  3646. else
  3647. {
  3648. HandleArbSeek(false);
  3649. }
  3650. }
  3651. else if (action == ACTION_RIGHT)
  3652. {
  3653. if (seekamount == 0) // 1 frame
  3654. DoFastForward(1, kInaccuracyNone);
  3655. else if (seekamount > 0)
  3656. {
  3657. // Use fully-accurate seeks for less than 1 second.
  3658. DoFastForwardSecs(seekamount, seekamount < 1.0F ? kInaccuracyNone :
  3659. kInaccuracyEditor, false);
  3660. }
  3661. else
  3662. {
  3663. HandleArbSeek(true);
  3664. }
  3665. }
  3666. else if (action == ACTION_LOADCOMMSKIP)
  3667. {
  3668. if (m_commBreakMap.HasMap())
  3669. {
  3670. frm_dir_map_t map;
  3671. m_commBreakMap.GetMap(map);
  3672. m_deleteMap.LoadCommBreakMap(map);
  3673. }
  3674. }
  3675. else if (action == ACTION_PREVCUT)
  3676. {
  3677. float old_seekamount = m_deleteMap.GetSeekAmount();
  3678. m_deleteMap.SetSeekAmount(-2);
  3679. HandleArbSeek(false);
  3680. m_deleteMap.SetSeekAmount(old_seekamount);
  3681. }
  3682. else if (action == ACTION_NEXTCUT)
  3683. {
  3684. float old_seekamount = m_deleteMap.GetSeekAmount();
  3685. m_deleteMap.SetSeekAmount(-2);
  3686. HandleArbSeek(true);
  3687. m_deleteMap.SetSeekAmount(old_seekamount);
  3688. }
  3689. #define FFREW_MULTICOUNT 10.0F
  3690. else if (action == ACTION_BIGJUMPREW)
  3691. {
  3692. if (seekamount == 0)
  3693. DoRewind(FFREW_MULTICOUNT, kInaccuracyNone);
  3694. else if (seekamount > 0)
  3695. {
  3696. DoRewindSecs(seekamount * FFREW_MULTICOUNT,
  3697. kInaccuracyEditor, false);
  3698. }
  3699. else
  3700. {
  3701. DoRewindSecs(FFREW_MULTICOUNT / 2,
  3702. kInaccuracyNone, false);
  3703. }
  3704. }
  3705. else if (action == ACTION_BIGJUMPFWD)
  3706. {
  3707. if (seekamount == 0)
  3708. DoFastForward(FFREW_MULTICOUNT, kInaccuracyNone);
  3709. else if (seekamount > 0)
  3710. {
  3711. DoFastForwardSecs(seekamount * FFREW_MULTICOUNT,
  3712. kInaccuracyEditor, false);
  3713. }
  3714. else
  3715. {
  3716. DoFastForwardSecs(FFREW_MULTICOUNT / 2,
  3717. kInaccuracyNone, false);
  3718. }
  3719. }
  3720. else if (action == ACTION_SELECT)
  3721. {
  3722. m_deleteMap.NewCut(frame);
  3723. SetOSDMessage(tr("New cut added."), kOSDTimeout_Short);
  3724. refresh = true;
  3725. }
  3726. else if (action == "DELETE")
  3727. {
  3728. m_deleteMap.Delete(frame, tr("Delete"));
  3729. refresh = true;
  3730. }
  3731. else if (action == "REVERT")
  3732. {
  3733. m_deleteMap.LoadMap(tr("Undo Changes"));
  3734. refresh = true;
  3735. }
  3736. else if (action == "REVERTEXIT")
  3737. {
  3738. DisableEdit(0);
  3739. refresh = false;
  3740. }
  3741. else if (action == ACTION_SAVEMAP)
  3742. {
  3743. m_deleteMap.SaveMap();
  3744. refresh = true;
  3745. }
  3746. else if (action == "EDIT" || action == "SAVEEXIT")
  3747. {
  3748. DisableEdit(1);
  3749. refresh = false;
  3750. }
  3751. else
  3752. {
  3753. QString undoMessage = m_deleteMap.GetUndoMessage();
  3754. QString redoMessage = m_deleteMap.GetRedoMessage();
  3755. handled = m_deleteMap.HandleAction(action, frame);
  3756. if (handled && (action == "CUTTOBEGINNING" ||
  3757. action == "CUTTOEND" || action == "NEWCUT"))
  3758. {
  3759. SetOSDMessage(tr("New cut added."), kOSDTimeout_Short);
  3760. }
  3761. else if (handled && action == "UNDO")
  3762. {
  3763. //: %1 is the undo message
  3764. SetOSDMessage(tr("Undo - %1").arg(undoMessage),
  3765. kOSDTimeout_Short);
  3766. }
  3767. else if (handled && action == "REDO")
  3768. {
  3769. //: %1 is the redo message
  3770. SetOSDMessage(tr("Redo - %1").arg(redoMessage),
  3771. kOSDTimeout_Short);
  3772. }
  3773. }
  3774. }
  3775. if (handled && refresh)
  3776. {
  3777. m_osdLock.lock();
  3778. if (m_osd)
  3779. {
  3780. m_deleteMap.UpdateOSD(m_framesPlayed, m_videoFrameRate, m_osd);
  3781. }
  3782. m_osdLock.unlock();
  3783. }
  3784. return handled;
  3785. }
  3786. bool MythPlayer::IsInDelete(uint64_t frame)
  3787. {
  3788. return m_deleteMap.IsInDelete(frame);
  3789. }
  3790. uint64_t MythPlayer::GetNearestMark(uint64_t frame, bool right)
  3791. {
  3792. return m_deleteMap.GetNearestMark(frame, right);
  3793. }
  3794. bool MythPlayer::IsTemporaryMark(uint64_t frame)
  3795. {
  3796. return m_deleteMap.IsTemporaryMark(frame);
  3797. }
  3798. bool MythPlayer::HasTemporaryMark(void)
  3799. {
  3800. return m_deleteMap.HasTemporaryMark();
  3801. }
  3802. void MythPlayer::HandleArbSeek(bool right)
  3803. {
  3804. if (m_deleteMap.GetSeekAmount() == -2)
  3805. {
  3806. uint64_t framenum = m_deleteMap.GetNearestMark(m_framesPlayed, right);
  3807. if (right && (framenum > m_framesPlayed))
  3808. DoFastForward(framenum - m_framesPlayed, kInaccuracyNone);
  3809. else if (!right && (m_framesPlayed > framenum))
  3810. DoRewind(m_framesPlayed - framenum, kInaccuracyNone);
  3811. }
  3812. else
  3813. {
  3814. if (right)
  3815. DoFastForward(2, kInaccuracyFull);
  3816. else
  3817. DoRewind(2, kInaccuracyFull);
  3818. }
  3819. }
  3820. AspectOverrideMode MythPlayer::GetAspectOverride(void) const
  3821. {
  3822. if (m_videoOutput)
  3823. return m_videoOutput->GetAspectOverride();
  3824. return kAspect_Off;
  3825. }
  3826. AdjustFillMode MythPlayer::GetAdjustFill(void) const
  3827. {
  3828. if (m_videoOutput)
  3829. return m_videoOutput->GetAdjustFill();
  3830. return kAdjustFill_Off;
  3831. }
  3832. void MythPlayer::ToggleAspectOverride(AspectOverrideMode aspectMode)
  3833. {
  3834. if (m_videoOutput)
  3835. {
  3836. m_videoOutput->ToggleAspectOverride(aspectMode);
  3837. ReinitOSD();
  3838. }
  3839. }
  3840. void MythPlayer::ToggleAdjustFill(AdjustFillMode adjustfillMode)
  3841. {
  3842. if (m_videoOutput)
  3843. {
  3844. m_detectLetterBox->SetDetectLetterbox(false);
  3845. m_videoOutput->ToggleAdjustFill(adjustfillMode);
  3846. ReinitOSD();
  3847. }
  3848. }
  3849. void MythPlayer::Zoom(ZoomDirection direction)
  3850. {
  3851. if (m_videoOutput)
  3852. {
  3853. m_videoOutput->Zoom(direction);
  3854. ReinitOSD();
  3855. }
  3856. }
  3857. void MythPlayer::ToggleMoveBottomLine(void)
  3858. {
  3859. if (m_videoOutput)
  3860. {
  3861. m_videoOutput->ToggleMoveBottomLine();
  3862. ReinitOSD();
  3863. }
  3864. }
  3865. void MythPlayer::SaveBottomLine(void)
  3866. {
  3867. if (m_videoOutput)
  3868. m_videoOutput->SaveBottomLine();
  3869. }
  3870. bool MythPlayer::IsEmbedding(void)
  3871. {
  3872. if (m_videoOutput)
  3873. return m_videoOutput->IsEmbedding();
  3874. return false;
  3875. }
  3876. bool MythPlayer::HasTVChainNext(void) const
  3877. {
  3878. return m_playerCtx->m_tvchain && m_playerCtx->m_tvchain->HasNext();
  3879. }
  3880. /** \fn MythPlayer::GetScreenGrab(int,int&,int&,int&,float&)
  3881. * \brief Returns a one RGB frame grab from a video.
  3882. *
  3883. * User is responsible for deleting the buffer with delete[].
  3884. * This also tries to skip any commercial breaks for a more
  3885. * useful screen grab for previews.
  3886. *
  3887. * Warning: Don't use this on something you're playing!
  3888. *
  3889. * \param secondsin [in] Seconds to seek into the buffer
  3890. * \param bufflen [out] Size of buffer returned in bytes
  3891. * \param vw [out] Width of buffer returned
  3892. * \param vh [out] Height of buffer returned
  3893. * \param ar [out] Aspect of buffer returned
  3894. */
  3895. char *MythPlayer::GetScreenGrab(int SecondsIn, int &BufferSize,
  3896. int &FrameWidth, int &FrameHeight, float &AspectRatio)
  3897. {
  3898. auto frameNum = static_cast<uint64_t>(SecondsIn * m_videoFrameRate);
  3899. return GetScreenGrabAtFrame(frameNum, false, BufferSize, FrameWidth, FrameHeight, AspectRatio);
  3900. }
  3901. /**
  3902. * \brief Returns a one RGB frame grab from a video.
  3903. *
  3904. * User is responsible for deleting the buffer with delete[].
  3905. * This also tries to skip any commercial breaks for a more
  3906. * useful screen grab for previews.
  3907. *
  3908. * Warning: Don't use this on something you're playing!
  3909. *
  3910. * \param frameNum [in] Frame number to capture
  3911. * \param absolute [in] If False, make sure we aren't in cutlist or Comm brk
  3912. * \param bufflen [out] Size of buffer returned in bytes
  3913. * \param vw [out] Width of buffer returned
  3914. * \param vh [out] Height of buffer returned
  3915. * \param ar [out] Aspect of buffer returned
  3916. */
  3917. char *MythPlayer::GetScreenGrabAtFrame(uint64_t FrameNum, bool Absolute,
  3918. int &BufferSize, int &FrameWidth, int &FrameHeight,
  3919. float &AspectRatio)
  3920. {
  3921. BufferSize = 0;
  3922. FrameWidth = FrameHeight = 0;
  3923. AspectRatio = 0;
  3924. if (OpenFile(0) < 0)
  3925. {
  3926. LOG(VB_GENERAL, LOG_ERR, LOC + "Could not open file for preview.");
  3927. return nullptr;
  3928. }
  3929. if ((m_videoDim.width() <= 0) || (m_videoDim.height() <= 0))
  3930. {
  3931. LOG(VB_PLAYBACK, LOG_ERR, LOC +
  3932. QString("Video Resolution invalid %1x%2")
  3933. .arg(m_videoDim.width()).arg(m_videoDim.height()));
  3934. // This is probably an audio file, just return a grey frame.
  3935. FrameWidth = 640;
  3936. FrameHeight = 480;
  3937. AspectRatio = 4.0F / 3.0F;
  3938. BufferSize = FrameWidth * FrameHeight * 4;
  3939. char* result = new char[BufferSize];
  3940. memset(result, 0x3f, static_cast<size_t>(BufferSize) * sizeof(char));
  3941. return result;
  3942. }
  3943. if (!InitVideo())
  3944. {
  3945. LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to initialize video for screen grab.");
  3946. return nullptr;
  3947. }
  3948. ClearAfterSeek();
  3949. if (!m_decoderThread)
  3950. DecoderStart(true /*start paused*/);
  3951. uint64_t dummy = 0;
  3952. SeekForScreenGrab(dummy, FrameNum, Absolute);
  3953. int tries = 0;
  3954. while (!m_videoOutput->ValidVideoFrames() && ((tries++) < 500))
  3955. {
  3956. m_decodeOneFrame = true;
  3957. usleep(10000);
  3958. if ((tries & 10) == 10)
  3959. LOG(VB_PLAYBACK, LOG_INFO, LOC + "ScreenGrab: Waited 100ms for video frame");
  3960. }
  3961. VideoFrame *frame = nullptr;
  3962. if (!(frame = m_videoOutput->GetLastDecodedFrame()))
  3963. return nullptr;
  3964. if (!frame->buf)
  3965. return nullptr;
  3966. if (frame->interlaced_frame)
  3967. {
  3968. // Use medium quality - which is currently yadif
  3969. frame->deinterlace_double = DEINT_NONE;
  3970. frame->deinterlace_allowed = frame->deinterlace_single = DEINT_CPU | DEINT_MEDIUM;
  3971. MythDeinterlacer deinterlacer;
  3972. deinterlacer.Filter(frame, kScan_Interlaced, nullptr, true);
  3973. }
  3974. unsigned char *result = CreateBuffer(FMT_RGB32, m_videoDim.width(), m_videoDim.height());
  3975. MythAVCopy copyCtx;
  3976. AVFrame retbuf;
  3977. memset(&retbuf, 0, sizeof(AVFrame));
  3978. copyCtx.Copy(&retbuf, frame, result, AV_PIX_FMT_RGB32);
  3979. FrameWidth = m_videoDispDim.width();
  3980. FrameHeight = m_videoDispDim.height();
  3981. AspectRatio = frame->aspect;
  3982. if (frame)
  3983. DiscardVideoFrame(frame);
  3984. return reinterpret_cast<char*>(result);
  3985. }
  3986. void MythPlayer::SeekForScreenGrab(uint64_t &number, uint64_t frameNum,
  3987. bool absolute)
  3988. {
  3989. number = frameNum;
  3990. if (number >= m_totalFrames)
  3991. {
  3992. LOG(VB_PLAYBACK, LOG_ERR, LOC +
  3993. "Screen grab requested for frame number beyond end of file.");
  3994. number = m_totalFrames / 2;
  3995. }
  3996. if (!absolute && m_hasFullPositionMap)
  3997. {
  3998. m_bookmarkSeek = GetBookmark();
  3999. // Use the bookmark if we should, otherwise make sure we aren't
  4000. // in the cutlist or a commercial break
  4001. if (m_bookmarkSeek > 30)
  4002. {
  4003. number = m_bookmarkSeek;
  4004. }
  4005. else
  4006. {
  4007. uint64_t oldnumber = number;
  4008. m_deleteMap.LoadMap();
  4009. m_commBreakMap.LoadMap(m_playerCtx, m_framesPlayed);
  4010. bool started_in_break_map = false;
  4011. while (m_commBreakMap.IsInCommBreak(number) ||
  4012. IsInDelete(number))
  4013. {
  4014. started_in_break_map = true;
  4015. number += (uint64_t) (30 * m_videoFrameRate);
  4016. if (number >= m_totalFrames)
  4017. {
  4018. number = oldnumber;
  4019. break;
  4020. }
  4021. }
  4022. // Advance a few seconds from the end of the break
  4023. if (started_in_break_map)
  4024. {
  4025. oldnumber = number;
  4026. number += (long long) (10 * m_videoFrameRate);
  4027. if (number >= m_totalFrames)
  4028. number = oldnumber;
  4029. }
  4030. }
  4031. }
  4032. DiscardVideoFrame(m_videoOutput->GetLastDecodedFrame());
  4033. DoJumpToFrame(number, kInaccuracyNone);
  4034. }
  4035. /** \fn MythPlayer::GetRawVideoFrame(long long)
  4036. * \brief Returns a specific frame from the video.
  4037. *
  4038. * NOTE: You must call DiscardVideoFrame(VideoFrame*) on
  4039. * the frame returned, as this marks the frame as
  4040. * being used and hence unavailable for decoding.
  4041. */
  4042. VideoFrame* MythPlayer::GetRawVideoFrame(long long frameNumber)
  4043. {
  4044. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  4045. if (m_playerCtx->m_playingInfo)
  4046. m_playerCtx->m_playingInfo->UpdateInUseMark();
  4047. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  4048. if (!m_decoderThread)
  4049. DecoderStart(false);
  4050. if (frameNumber >= 0)
  4051. {
  4052. DoJumpToFrame(frameNumber, kInaccuracyNone);
  4053. ClearAfterSeek();
  4054. }
  4055. int tries = 0;
  4056. while (!m_videoOutput->ValidVideoFrames() && ((tries++) < 100))
  4057. {
  4058. m_decodeOneFrame = true;
  4059. usleep(10000);
  4060. if ((tries & 10) == 10)
  4061. LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms for video frame");
  4062. }
  4063. m_videoOutput->StartDisplayingFrame();
  4064. return m_videoOutput->GetLastShownFrame();
  4065. }
  4066. QString MythPlayer::GetEncodingType(void) const
  4067. {
  4068. if (m_decoder)
  4069. return get_encoding_type(m_decoder->GetVideoCodecID());
  4070. return QString();
  4071. }
  4072. void MythPlayer::GetCodecDescription(InfoMap &infoMap)
  4073. {
  4074. infoMap["audiocodec"] = ff_codec_id_string(m_audio.GetCodec());
  4075. infoMap["audiochannels"] = QString::number(m_audio.GetOrigChannels());
  4076. int width = m_videoDispDim.width();
  4077. int height = m_videoDispDim.height();
  4078. infoMap["videocodec"] = GetEncodingType();
  4079. if (m_decoder)
  4080. infoMap["videocodecdesc"] = m_decoder->GetRawEncodingType();
  4081. infoMap["videowidth"] = QString::number(width);
  4082. infoMap["videoheight"] = QString::number(height);
  4083. infoMap["videoframerate"] = QString::number(m_videoFrameRate, 'f', 2);
  4084. infoMap["deinterlacer"] = DeinterlacerName(m_lastDeinterlacer,
  4085. m_lastDeinterlacer2x, m_lastFrameCodec);
  4086. if (width < 640)
  4087. return;
  4088. bool interlaced = is_interlaced(m_scan);
  4089. if (width == 1920 || height == 1080 || height == 1088)
  4090. infoMap["videodescrip"] = interlaced ? "HD_1080_I" : "HD_1080_P";
  4091. else if ((width == 1280 || height == 720) && !interlaced)
  4092. infoMap["videodescrip"] = "HD_720_P";
  4093. else if (height >= 720)
  4094. infoMap["videodescrip"] = "HD";
  4095. else infoMap["videodescrip"] = "SD";
  4096. }
  4097. bool MythPlayer::GetRawAudioState(void) const
  4098. {
  4099. if (m_decoder)
  4100. return m_decoder->GetRawAudioState();
  4101. return false;
  4102. }
  4103. QString MythPlayer::GetXDS(const QString &key) const
  4104. {
  4105. if (!m_decoder)
  4106. return QString();
  4107. return m_decoder->GetXDS(key);
  4108. }
  4109. void MythPlayer::InitForTranscode(bool copyaudio, bool copyvideo)
  4110. {
  4111. // Are these really needed?
  4112. SetPlaying(true);
  4113. m_keyframeDist = 30;
  4114. if (!InitVideo())
  4115. {
  4116. LOG(VB_GENERAL, LOG_ERR, LOC +
  4117. "Unable to initialize video for transcode.");
  4118. SetPlaying(false);
  4119. return;
  4120. }
  4121. m_framesPlayed = 0;
  4122. ClearAfterSeek();
  4123. if (copyvideo && m_decoder)
  4124. m_decoder->SetRawVideoState(true);
  4125. if (copyaudio && m_decoder)
  4126. m_decoder->SetRawAudioState(true);
  4127. if (m_decoder)
  4128. {
  4129. m_decoder->SetSeekSnap(0);
  4130. }
  4131. }
  4132. bool MythPlayer::TranscodeGetNextFrame(
  4133. int &did_ff, bool &is_key, bool honorCutList)
  4134. {
  4135. m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
  4136. if (m_playerCtx->m_playingInfo)
  4137. m_playerCtx->m_playingInfo->UpdateInUseMark();
  4138. m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
  4139. int64_t lastDecodedFrameNumber =
  4140. m_videoOutput->GetLastDecodedFrame()->frameNumber;
  4141. if ((lastDecodedFrameNumber == 0) && honorCutList)
  4142. m_deleteMap.TrackerReset(0);
  4143. if (!m_decoderThread)
  4144. DecoderStart(true/*start paused*/);
  4145. if (!m_decoder)
  4146. return false;
  4147. {
  4148. QMutexLocker decoderlocker(&m_decoderChangeLock);
  4149. if (!DoGetFrame(kDecodeAV))
  4150. return false;
  4151. }
  4152. if (GetEof() != kEofStateNone)
  4153. return false;
  4154. if (honorCutList && !m_deleteMap.IsEmpty())
  4155. {
  4156. if (m_totalFrames && lastDecodedFrameNumber >= (int64_t)m_totalFrames)
  4157. return false;
  4158. uint64_t jumpto = 0;
  4159. if (m_deleteMap.TrackerWantsToJump(lastDecodedFrameNumber, jumpto))
  4160. {
  4161. LOG(VB_GENERAL, LOG_INFO, LOC +
  4162. QString("Fast-Forwarding from %1 to %2")
  4163. .arg(lastDecodedFrameNumber).arg(jumpto));
  4164. if (jumpto >= m_totalFrames)
  4165. {
  4166. SetEof(kEofStateDelayed);
  4167. return false;
  4168. }
  4169. // For 0.25, move this to DoJumpToFrame(jumpto)
  4170. WaitForSeek(jumpto, 0);
  4171. m_decoder->ClearStoredData();
  4172. ClearAfterSeek();
  4173. m_decoderChangeLock.lock();
  4174. DoGetFrame(kDecodeAV);
  4175. m_decoderChangeLock.unlock();
  4176. did_ff = 1;
  4177. }
  4178. }
  4179. if (GetEof() != kEofStateNone)
  4180. return false;
  4181. is_key = m_decoder->IsLastFrameKey();
  4182. return true;
  4183. }
  4184. long MythPlayer::UpdateStoredFrameNum(long curFrameNum)
  4185. {
  4186. if (m_decoder)
  4187. return m_decoder->UpdateStoredFrameNum(curFrameNum);
  4188. return 0;
  4189. }
  4190. void MythPlayer::SetCutList(const frm_dir_map_t &newCutList)
  4191. {
  4192. m_deleteMap.SetMap(newCutList);
  4193. }
  4194. bool MythPlayer::WriteStoredData(MythMediaBuffer *OutBuffer,
  4195. bool Writevideo, long TimecodeOffset)
  4196. {
  4197. if (!m_decoder)
  4198. return false;
  4199. if (Writevideo && !m_decoder->GetRawVideoState())
  4200. Writevideo = false;
  4201. m_decoder->WriteStoredData(OutBuffer, Writevideo, TimecodeOffset);
  4202. return Writevideo;
  4203. }
  4204. void MythPlayer::SetCommBreakMap(frm_dir_map_t &newMap)
  4205. {
  4206. m_commBreakMap.SetMap(newMap, m_framesPlayed);
  4207. m_forcePositionMapSync = true;
  4208. }
  4209. int MythPlayer::GetStatusbarPos(void) const
  4210. {
  4211. double spos = 0.0;
  4212. if (m_liveTV || IsWatchingInprogress())
  4213. {
  4214. spos = 1000.0 * m_framesPlayed / m_playerCtx->m_recorder->GetFramesWritten();
  4215. }
  4216. else if (m_totalFrames)
  4217. {
  4218. spos = 1000.0 * m_framesPlayed / m_totalFrames;
  4219. }
  4220. return((int)spos);
  4221. }
  4222. void MythPlayer::GetPlaybackData(InfoMap &infoMap)
  4223. {
  4224. QString samplerate = MythMediaBuffer::BitrateToString(m_audio.GetSampleRate(), true);
  4225. infoMap.insert("samplerate", samplerate);
  4226. infoMap.insert("filename", m_playerCtx->m_buffer->GetSafeFilename());
  4227. infoMap.insert("decoderrate", m_playerCtx->m_buffer->GetDecoderRate());
  4228. infoMap.insert("storagerate", m_playerCtx->m_buffer->GetStorageRate());
  4229. infoMap.insert("bufferavail", m_playerCtx->m_buffer->GetAvailableBuffer());
  4230. infoMap.insert("buffersize", QString::number(m_playerCtx->m_buffer->GetBufferSize() >> 20));
  4231. int avsync = m_avsyncAvg / 1000;
  4232. infoMap.insert("avsync", tr("%1 ms").arg(avsync));
  4233. if (m_videoOutput)
  4234. {
  4235. QString frames = QString("%1/%2").arg(m_videoOutput->ValidVideoFrames())
  4236. .arg(m_videoOutput->FreeVideoFrames());
  4237. infoMap.insert("videoframes", frames);
  4238. }
  4239. if (m_decoder)
  4240. infoMap["videodecoder"] = m_decoder->GetCodecDecoderName();
  4241. if (m_outputJmeter)
  4242. {
  4243. infoMap["framerate"] = QString("%1%2%3")
  4244. .arg(m_outputJmeter->GetLastFPS(), 0, 'f', 2)
  4245. .arg(QChar(0xB1, 0))
  4246. .arg(m_outputJmeter->GetLastSD(), 0, 'f', 2);
  4247. infoMap["load"] = m_outputJmeter->GetLastCPUStats();
  4248. }
  4249. GetCodecDescription(infoMap);
  4250. }
  4251. int64_t MythPlayer::GetSecondsPlayed(bool honorCutList, int divisor)
  4252. {
  4253. int64_t pos = TranslatePositionFrameToMs(m_framesPlayed, honorCutList);
  4254. LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
  4255. QString("GetSecondsPlayed: framesPlayed %1, honorCutList %2, divisor %3, pos %4")
  4256. .arg(m_framesPlayed).arg(honorCutList).arg(divisor).arg(pos));
  4257. return TranslatePositionFrameToMs(m_framesPlayed, honorCutList) / divisor;
  4258. }
  4259. int64_t MythPlayer::GetTotalSeconds(bool honorCutList, int divisor) const
  4260. {
  4261. uint64_t pos = m_totalFrames;
  4262. if (IsWatchingInprogress())
  4263. pos = UINT64_MAX;
  4264. return TranslatePositionFrameToMs(pos, honorCutList) / divisor;
  4265. }
  4266. // Returns the total frame count, as totalFrames for a completed
  4267. // recording, or the most recent frame count from the recorder for
  4268. // live TV or an in-progress recording.
  4269. uint64_t MythPlayer::GetCurrentFrameCount(void) const
  4270. {
  4271. uint64_t result = m_totalFrames;
  4272. if (IsWatchingInprogress())
  4273. result = m_playerCtx->m_recorder->GetFramesWritten();
  4274. return result;
  4275. }
  4276. // Finds the frame number associated with the given time offset. A
  4277. // positive offset or +0.0F indicate offset from the beginning. A
  4278. // negative offset or -0.0F indicate offset from the end. Limit the
  4279. // result to within bounds of the video.
  4280. uint64_t MythPlayer::FindFrame(float offset, bool use_cutlist) const
  4281. {
  4282. bool islivetvcur = (m_liveTV && m_playerCtx->m_tvchain &&
  4283. !m_playerCtx->m_tvchain->HasNext());
  4284. uint64_t length_ms = TranslatePositionFrameToMs(m_totalFrames, use_cutlist);
  4285. uint64_t position_ms = 0;
  4286. if (signbit(offset))
  4287. {
  4288. // Always get an updated totalFrame value for in progress recordings
  4289. if (islivetvcur || IsWatchingInprogress())
  4290. {
  4291. uint64_t framesWritten = m_playerCtx->m_recorder->GetFramesWritten();
  4292. if (m_totalFrames < framesWritten)
  4293. {
  4294. // Known duration is less than what the backend reported, use new value
  4295. length_ms =
  4296. TranslatePositionFrameToMs(framesWritten, use_cutlist);
  4297. }
  4298. }
  4299. uint64_t offset_ms = llroundf(-offset * 1000);
  4300. position_ms = (offset_ms > length_ms) ? 0 : length_ms - offset_ms;
  4301. }
  4302. else
  4303. {
  4304. position_ms = llroundf(offset * 1000);
  4305. if (offset > length_ms)
  4306. {
  4307. // Make sure we have an updated totalFrames
  4308. if ((islivetvcur || IsWatchingInprogress()) &&
  4309. (length_ms < offset))
  4310. {
  4311. long long framesWritten =
  4312. m_playerCtx->m_recorder->GetFramesWritten();
  4313. length_ms =
  4314. TranslatePositionFrameToMs(framesWritten, use_cutlist);
  4315. }
  4316. position_ms = min(position_ms, length_ms);
  4317. }
  4318. }
  4319. return TranslatePositionMsToFrame(position_ms, use_cutlist);
  4320. }
  4321. void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
  4322. {
  4323. if (!m_decoder)
  4324. return;
  4325. bool islive = false;
  4326. info.text.insert("chapteridx", QString());
  4327. info.text.insert("totalchapters", QString());
  4328. info.text.insert("titleidx", QString());
  4329. info.text.insert("totaltitles", QString());
  4330. info.text.insert("angleidx", QString());
  4331. info.text.insert("totalangles", QString());
  4332. info.values.insert("position", 0);
  4333. info.values.insert("progbefore", 0);
  4334. info.values.insert("progafter", 0);
  4335. int playbackLen = 0;
  4336. bool fixed_playbacklen = false;
  4337. if (m_decoder->GetCodecDecoderName() == "nuppel")
  4338. {
  4339. playbackLen = m_totalLength;
  4340. fixed_playbacklen = true;
  4341. }
  4342. if (m_liveTV && m_playerCtx->m_tvchain)
  4343. {
  4344. info.values["progbefore"] = (int)m_playerCtx->m_tvchain->HasPrev();
  4345. info.values["progafter"] = (int)m_playerCtx->m_tvchain->HasNext();
  4346. playbackLen = m_playerCtx->m_tvchain->GetLengthAtCurPos();
  4347. islive = true;
  4348. fixed_playbacklen = true;
  4349. }
  4350. else if (IsWatchingInprogress())
  4351. {
  4352. islive = true;
  4353. }
  4354. else
  4355. {
  4356. int chapter = GetCurrentChapter();
  4357. int chapters = GetNumChapters();
  4358. if (chapter && chapters > 1)
  4359. {
  4360. info.text["chapteridx"] = QString::number(chapter + 1);
  4361. info.text["totalchapters"] = QString::number(chapters);
  4362. }
  4363. int title = GetCurrentTitle();
  4364. int titles = GetNumTitles();
  4365. if (title && titles > 1)
  4366. {
  4367. info.text["titleidx"] = QString::number(title + 1);
  4368. info.text["totaltitles"] = QString::number(titles);
  4369. }
  4370. int angle = GetCurrentAngle();
  4371. int angles = GetNumAngles();
  4372. if (angle && angles > 1)
  4373. {
  4374. info.text["angleidx"] = QString::number(angle + 1);
  4375. info.text["totalangles"] = QString::number(angles);
  4376. }
  4377. }
  4378. // Set the raw values, followed by the translated values.
  4379. for (int i = 0; i < 2 ; ++i)
  4380. {
  4381. bool honorCutList = (i > 0);
  4382. bool stillFrame = false;
  4383. int pos = 0;
  4384. QString relPrefix = (honorCutList ? "rel" : "");
  4385. if (!fixed_playbacklen)
  4386. playbackLen = GetTotalSeconds(honorCutList);
  4387. int secsplayed = GetSecondsPlayed(honorCutList);
  4388. stillFrame = (secsplayed < 0);
  4389. playbackLen = max(playbackLen, 0);
  4390. secsplayed = min(playbackLen, max(secsplayed, 0));
  4391. int secsbehind = max((playbackLen - secsplayed), 0);
  4392. if (playbackLen > 0)
  4393. pos = (int)(1000.0F * (secsplayed / (float)playbackLen));
  4394. info.values.insert(relPrefix + "secondsplayed", secsplayed);
  4395. info.values.insert(relPrefix + "totalseconds", playbackLen);
  4396. info.values[relPrefix + "position"] = pos;
  4397. QString text1;
  4398. QString text2;
  4399. QString text3;
  4400. if (paddedFields)
  4401. {
  4402. text1 = MythFormatTime(secsplayed, "HH:mm:ss");
  4403. text2 = MythFormatTime(playbackLen, "HH:mm:ss");
  4404. text3 = MythFormatTime(secsbehind, "HH:mm:ss");
  4405. }
  4406. else
  4407. {
  4408. QString fmt = (playbackLen >= ONEHOURINSEC) ? "H:mm:ss" : "mm:ss";
  4409. text1 = MythFormatTime(secsplayed, fmt);
  4410. text2 = MythFormatTime(playbackLen, fmt);
  4411. if (secsbehind >= ONEHOURINSEC)
  4412. {
  4413. text3 = MythFormatTime(secsbehind, "H:mm:ss");
  4414. }
  4415. else if (secsbehind >= ONEMININSEC)
  4416. {
  4417. text3 = MythFormatTime(secsbehind, "mm:ss");
  4418. }
  4419. else
  4420. {
  4421. text3 = tr("%n second(s)", "", secsbehind);
  4422. }
  4423. }
  4424. QString desc = stillFrame ? tr("Still Frame") :
  4425. tr("%1 of %2").arg(text1).arg(text2);
  4426. info.text[relPrefix + "description"] = desc;
  4427. info.text[relPrefix + "playedtime"] = text1;
  4428. info.text[relPrefix + "totaltime"] = text2;
  4429. info.text[relPrefix + "remainingtime"] = islive ? QString() : text3;
  4430. info.text[relPrefix + "behindtime"] = islive ? text3 : QString();
  4431. }
  4432. }
  4433. // If position == -1, it signifies that we are computing the current
  4434. // duration of an in-progress recording. In this case, we fetch the
  4435. // current frame rate and frame count from the recorder.
  4436. uint64_t MythPlayer::TranslatePositionFrameToMs(uint64_t position,
  4437. bool use_cutlist) const
  4438. {
  4439. float frameRate = GetFrameRate();
  4440. if (position == UINT64_MAX &&
  4441. m_playerCtx->m_recorder && m_playerCtx->m_recorder->IsValidRecorder())
  4442. {
  4443. float recorderFrameRate = m_playerCtx->m_recorder->GetFrameRate();
  4444. if (recorderFrameRate > 0)
  4445. frameRate = recorderFrameRate;
  4446. position = m_playerCtx->m_recorder->GetFramesWritten();
  4447. }
  4448. return m_deleteMap.TranslatePositionFrameToMs(position, frameRate,
  4449. use_cutlist);
  4450. }
  4451. int MythPlayer::GetNumChapters()
  4452. {
  4453. if (m_decoder)
  4454. return m_decoder->GetNumChapters();
  4455. return 0;
  4456. }
  4457. int MythPlayer::GetCurrentChapter()
  4458. {
  4459. if (m_decoder)
  4460. return m_decoder->GetCurrentChapter(m_framesPlayed);
  4461. return 0;
  4462. }
  4463. void MythPlayer::GetChapterTimes(QList<long long> &times)
  4464. {
  4465. if (m_decoder)
  4466. return m_decoder->GetChapterTimes(times);
  4467. }
  4468. bool MythPlayer::DoJumpChapter(int chapter)
  4469. {
  4470. int64_t desiredFrame = -1;
  4471. int total = GetNumChapters();
  4472. int current = GetCurrentChapter();
  4473. if (chapter < 0 || chapter > total)
  4474. {
  4475. if (chapter < 0)
  4476. {
  4477. chapter = current -1;
  4478. if (chapter < 0) chapter = 0;
  4479. }
  4480. else if (chapter > total)
  4481. {
  4482. chapter = current + 1;
  4483. if (chapter > total) chapter = total;
  4484. }
  4485. }
  4486. desiredFrame = GetChapter(chapter);
  4487. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  4488. QString("DoJumpChapter: current %1 want %2 (frame %3)")
  4489. .arg(current).arg(chapter).arg(desiredFrame));
  4490. if (desiredFrame < 0)
  4491. {
  4492. LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
  4493. m_jumpChapter = 0;
  4494. return false;
  4495. }
  4496. DoJumpToFrame(desiredFrame, kInaccuracyNone);
  4497. m_jumpChapter = 0;
  4498. return true;
  4499. }
  4500. int64_t MythPlayer::GetChapter(int chapter)
  4501. {
  4502. if (m_decoder)
  4503. return m_decoder->GetChapter(chapter);
  4504. return 0;
  4505. }
  4506. InteractiveTV *MythPlayer::GetInteractiveTV(void)
  4507. {
  4508. #ifdef USING_MHEG
  4509. if (!m_interactiveTV && m_itvEnabled && !FlagIsSet(kNoITV))
  4510. {
  4511. MythMultiLocker locker({&m_osdLock, &m_itvLock});
  4512. if (!m_interactiveTV && m_osd)
  4513. m_interactiveTV = new InteractiveTV(this);
  4514. }
  4515. #endif // USING_MHEG
  4516. return m_interactiveTV;
  4517. }
  4518. bool MythPlayer::ITVHandleAction(const QString &action)
  4519. {
  4520. bool result = false;
  4521. #ifdef USING_MHEG
  4522. if (!GetInteractiveTV())
  4523. return result;
  4524. QMutexLocker locker(&m_itvLock);
  4525. result = m_interactiveTV->OfferKey(action);
  4526. #else
  4527. Q_UNUSED(action);
  4528. #endif // USING_MHEG
  4529. return result;
  4530. }
  4531. /** \fn MythPlayer::ITVRestart(uint chanid, uint cardid, bool isLive)
  4532. * \brief Restart the MHEG/MHP engine.
  4533. */
  4534. void MythPlayer::ITVRestart(uint chanid, uint cardid, bool isLiveTV)
  4535. {
  4536. #ifdef USING_MHEG
  4537. if (!GetInteractiveTV())
  4538. return;
  4539. QMutexLocker locker(&m_itvLock);
  4540. m_interactiveTV->Restart(chanid, cardid, isLiveTV);
  4541. m_itvVisible = false;
  4542. #else
  4543. Q_UNUSED(chanid);
  4544. Q_UNUSED(cardid);
  4545. Q_UNUSED(isLiveTV);
  4546. #endif // USING_MHEG
  4547. }
  4548. // Called from the interactiveTV (MHIContext) thread
  4549. void MythPlayer::SetVideoResize(const QRect &videoRect)
  4550. {
  4551. QMutexLocker locker(&m_osdLock);
  4552. if (m_videoOutput)
  4553. m_videoOutput->SetVideoResize(videoRect);
  4554. }
  4555. /** \fn MythPlayer::SetAudioByComponentTag(int tag)
  4556. * \brief Selects the audio stream using the DVB component tag.
  4557. */
  4558. // Called from the interactiveTV (MHIContext) thread
  4559. bool MythPlayer::SetAudioByComponentTag(int tag)
  4560. {
  4561. QMutexLocker locker(&m_decoderChangeLock);
  4562. if (m_decoder)
  4563. return m_decoder->SetAudioByComponentTag(tag);
  4564. return false;
  4565. }
  4566. /** \fn MythPlayer::SetVideoByComponentTag(int tag)
  4567. * \brief Selects the video stream using the DVB component tag.
  4568. */
  4569. // Called from the interactiveTV (MHIContext) thread
  4570. bool MythPlayer::SetVideoByComponentTag(int tag)
  4571. {
  4572. QMutexLocker locker(&m_decoderChangeLock);
  4573. if (m_decoder)
  4574. return m_decoder->SetVideoByComponentTag(tag);
  4575. return false;
  4576. }
  4577. static inline double SafeFPS(DecoderBase *m_decoder)
  4578. {
  4579. if (!m_decoder)
  4580. return 25;
  4581. double fps = m_decoder->GetFPS();
  4582. return fps > 0 ? fps : 25.0;
  4583. }
  4584. // Called from the interactiveTV (MHIContext) thread
  4585. bool MythPlayer::SetStream(const QString &stream)
  4586. {
  4587. // The stream name is empty if the stream is closing
  4588. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetStream '%1'").arg(stream));
  4589. QMutexLocker locker(&m_streamLock);
  4590. m_newStream = stream;
  4591. locker.unlock();
  4592. // Stream will be changed by JumpToStream called from EventLoop
  4593. // If successful will call m_interactiveTV->StreamStarted();
  4594. if (stream.isEmpty() && m_playerCtx->m_tvchain &&
  4595. m_playerCtx->m_buffer->GetType() == kMythBufferMHEG)
  4596. {
  4597. // Restore livetv
  4598. SetEof(kEofStateDelayed);
  4599. m_playerCtx->m_tvchain->JumpToNext(false, 0);
  4600. m_playerCtx->m_tvchain->JumpToNext(true, 0);
  4601. }
  4602. return !stream.isEmpty();
  4603. }
  4604. // Called from EventLoop pn the main application thread
  4605. void MythPlayer::JumpToStream(const QString &stream)
  4606. {
  4607. LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToStream - begin");
  4608. if (stream.isEmpty())
  4609. return; // Shouldn't happen
  4610. Pause();
  4611. ResetCaptions();
  4612. ProgramInfo pginfo(stream);
  4613. SetPlayingInfo(pginfo);
  4614. if (m_playerCtx->m_buffer->GetType() != kMythBufferMHEG)
  4615. m_playerCtx->m_buffer = new MythInteractiveBuffer(stream, m_playerCtx->m_buffer);
  4616. else
  4617. m_playerCtx->m_buffer->OpenFile(stream);
  4618. if (!m_playerCtx->m_buffer->IsOpen())
  4619. {
  4620. LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToStream buffer OpenFile failed");
  4621. SetEof(kEofStateImmediate);
  4622. SetErrored(tr("Error opening remote stream buffer"));
  4623. return;
  4624. }
  4625. m_watchingRecording = false;
  4626. m_totalLength = 0;
  4627. m_totalFrames = 0;
  4628. m_totalDuration = 0;
  4629. if (OpenFile(120) < 0) // 120 retries ~= 60 seconds
  4630. {
  4631. LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToStream OpenFile failed.");
  4632. SetEof(kEofStateImmediate);
  4633. SetErrored(tr("Error opening remote stream"));
  4634. return;
  4635. }
  4636. if (m_totalLength == 0)
  4637. {
  4638. long long len = m_playerCtx->m_buffer->GetRealFileSize();
  4639. m_totalLength = (int)(len / ((m_decoder->GetRawBitrate() * 1000) / 8));
  4640. m_totalFrames = (int)(m_totalLength * SafeFPS(m_decoder));
  4641. }
  4642. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  4643. QString("JumpToStream length %1 bytes @ %2 Kbps = %3 Secs, %4 frames @ %5 fps")
  4644. .arg(m_playerCtx->m_buffer->GetRealFileSize()).arg(m_decoder->GetRawBitrate())
  4645. .arg(m_totalLength).arg(m_totalFrames).arg(m_decoder->GetFPS()) );
  4646. SetEof(kEofStateNone);
  4647. // the bitrate is reset by m_playerCtx->m_buffer->OpenFile()...
  4648. m_playerCtx->m_buffer->UpdateRawBitrate(m_decoder->GetRawBitrate());
  4649. m_decoder->SetProgramInfo(pginfo);
  4650. Play();
  4651. ChangeSpeed();
  4652. m_playerCtx->SetPlayerChangingBuffers(false);
  4653. #ifdef USING_MHEG
  4654. if (m_interactiveTV) m_interactiveTV->StreamStarted();
  4655. #endif
  4656. LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToStream - end");
  4657. }
  4658. // Called from the interactiveTV (MHIContext) thread
  4659. long MythPlayer::GetStreamPos()
  4660. {
  4661. return (long)((1000 * GetFramesPlayed()) / SafeFPS(m_decoder));
  4662. }
  4663. // Called from the interactiveTV (MHIContext) thread
  4664. long MythPlayer::GetStreamMaxPos()
  4665. {
  4666. long maxpos = (long)(1000 * (m_totalDuration > 0 ? m_totalDuration : m_totalLength));
  4667. long pos = GetStreamPos();
  4668. return maxpos > pos ? maxpos : pos;
  4669. }
  4670. // Called from the interactiveTV (MHIContext) thread
  4671. long MythPlayer::SetStreamPos(long ms)
  4672. {
  4673. auto frameNum = (uint64_t)((ms * SafeFPS(m_decoder)) / 1000);
  4674. LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetStreamPos %1 mS = frame %2, now=%3")
  4675. .arg(ms).arg(frameNum).arg(GetFramesPlayed()) );
  4676. JumpToFrame(frameNum);
  4677. return ms;
  4678. }
  4679. // Called from the interactiveTV (MHIContext) thread
  4680. void MythPlayer::StreamPlay(bool play)
  4681. {
  4682. if (play)
  4683. Play();
  4684. else
  4685. Pause();
  4686. }
  4687. /** \fn MythPlayer::SetDecoder(DecoderBase*)
  4688. * \brief Sets the stream decoder, deleting any existing recorder.
  4689. */
  4690. void MythPlayer::SetDecoder(DecoderBase *dec)
  4691. {
  4692. m_totalDecoderPause = true;
  4693. PauseDecoder();
  4694. {
  4695. while (!m_decoderChangeLock.tryLock(10))
  4696. LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
  4697. delete m_decoder;
  4698. m_decoder = dec;
  4699. m_decoderChangeLock.unlock();
  4700. }
  4701. // reset passthrough override
  4702. m_disablePassthrough = false;
  4703. syncWithAudioStretch();
  4704. m_totalDecoderPause = false;
  4705. }
  4706. bool MythPlayer::PosMapFromEnc(uint64_t start,
  4707. frm_pos_map_t &posMap,
  4708. frm_pos_map_t &durMap)
  4709. {
  4710. // Reads only new positionmap entries from encoder
  4711. if (!(m_liveTV || (m_playerCtx->m_recorder &&
  4712. m_playerCtx->m_recorder->IsValidRecorder())))
  4713. return false;
  4714. // if livetv, and we're not the last entry, don't get it from the encoder
  4715. if (HasTVChainNext())
  4716. return false;
  4717. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  4718. QString("Filling position map from %1 to %2") .arg(start).arg("end"));
  4719. m_playerCtx->m_recorder->FillPositionMap(start, -1, posMap);
  4720. m_playerCtx->m_recorder->FillDurationMap(start, -1, durMap);
  4721. return true;
  4722. }
  4723. void MythPlayer::SetErrored(const QString &reason)
  4724. {
  4725. QMutexLocker locker(&m_errorLock);
  4726. if (m_videoOutput)
  4727. m_errorType |= m_videoOutput->GetError();
  4728. if (m_errorMsg.isEmpty())
  4729. {
  4730. m_errorMsg = reason;
  4731. }
  4732. else
  4733. {
  4734. LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
  4735. }
  4736. }
  4737. void MythPlayer::ResetErrored(void)
  4738. {
  4739. QMutexLocker locker(&m_errorLock);
  4740. m_errorMsg = QString();
  4741. }
  4742. bool MythPlayer::IsErrored(void) const
  4743. {
  4744. QMutexLocker locker(&m_errorLock);
  4745. return !m_errorMsg.isEmpty();
  4746. }
  4747. QString MythPlayer::GetError(void) const
  4748. {
  4749. QMutexLocker locker(&m_errorLock);
  4750. return m_errorMsg;
  4751. }
  4752. void MythPlayer::ToggleNightMode(void)
  4753. {
  4754. if (!m_videoOutput)
  4755. return;
  4756. if (!(m_videoOutput->GetSupportedPictureAttributes() &
  4757. kPictureAttributeSupported_Brightness))
  4758. return;
  4759. int b = m_videoOutput->GetPictureAttribute(kPictureAttribute_Brightness);
  4760. int c = 0;
  4761. bool has_contrast = (m_videoOutput->GetSupportedPictureAttributes() &
  4762. kPictureAttributeSupported_Contrast) != 0;
  4763. if (has_contrast)
  4764. c = m_videoOutput->GetPictureAttribute(kPictureAttribute_Contrast);
  4765. int nm = gCoreContext->GetNumSetting("NightModeEnabled", 0);
  4766. QString msg;
  4767. if (!nm)
  4768. {
  4769. msg = tr("Enabled Night Mode");
  4770. b -= kNightModeBrightenssAdjustment;
  4771. c -= kNightModeContrastAdjustment;
  4772. }
  4773. else
  4774. {
  4775. msg = tr("Disabled Night Mode");
  4776. b += kNightModeBrightenssAdjustment;
  4777. c += kNightModeContrastAdjustment;
  4778. }
  4779. b = clamp(b, 0, 100);
  4780. c = clamp(c, 0, 100);
  4781. gCoreContext->SaveSetting("NightModeEnabled", nm ? "0" : "1");
  4782. m_videoOutput->SetPictureAttribute(kPictureAttribute_Brightness, b);
  4783. if (has_contrast)
  4784. m_videoOutput->SetPictureAttribute(kPictureAttribute_Contrast, c);
  4785. SetOSDMessage(msg, kOSDTimeout_Med);
  4786. }
  4787. bool MythPlayer::CanVisualise(void)
  4788. {
  4789. if (m_videoOutput)
  4790. return m_videoOutput->
  4791. CanVisualise(&m_audio, GetMythMainWindow()->GetRenderDevice());
  4792. return false;
  4793. }
  4794. bool MythPlayer::IsVisualising(void)
  4795. {
  4796. if (m_videoOutput)
  4797. return m_videoOutput->GetVisualisation();
  4798. return false;
  4799. }
  4800. QString MythPlayer::GetVisualiserName(void)
  4801. {
  4802. if (m_videoOutput)
  4803. return m_videoOutput->GetVisualiserName();
  4804. return QString("");
  4805. }
  4806. QStringList MythPlayer::GetVisualiserList(void)
  4807. {
  4808. if (m_videoOutput)
  4809. return m_videoOutput->GetVisualiserList();
  4810. return QStringList();
  4811. }
  4812. bool MythPlayer::EnableVisualisation(bool enable, const QString &name)
  4813. {
  4814. if (m_videoOutput)
  4815. return m_videoOutput->EnableVisualisation(&m_audio, enable, name);
  4816. return false;
  4817. }
  4818. /*! \brief Enable visualisation if possible, there is no video and user has requested.
  4819. */
  4820. void MythPlayer::AutoVisualise(void)
  4821. {
  4822. if (!m_videoOutput || !m_audio.HasAudioIn() || !m_videoDim.isEmpty())
  4823. return;
  4824. if (!CanVisualise() || IsVisualising())
  4825. return;
  4826. auto visualiser = gCoreContext->GetSetting("AudioVisualiser", "");
  4827. if (!visualiser.isEmpty())
  4828. EnableVisualisation(true, visualiser);
  4829. }
  4830. void MythPlayer::SetOSDMessage(const QString &msg, OSDTimeout timeout)
  4831. {
  4832. QMutexLocker locker(&m_osdLock);
  4833. if (!m_osd)
  4834. return;
  4835. InfoMap info;
  4836. info.insert("message_text", msg);
  4837. m_osd->SetText("osd_message", info, timeout);
  4838. }
  4839. void MythPlayer::SetOSDStatus(const QString &title, OSDTimeout timeout)
  4840. {
  4841. QMutexLocker locker(&m_osdLock);
  4842. if (!m_osd)
  4843. return;
  4844. osdInfo info;
  4845. calcSliderPos(info);
  4846. info.text.insert("title", title);
  4847. m_osd->SetText("osd_status", info.text, timeout);
  4848. m_osd->SetValues("osd_status", info.values, timeout);
  4849. }
  4850. void MythPlayer::SaveTotalDuration(void)
  4851. {
  4852. if (!m_decoder)
  4853. return;
  4854. m_decoder->SaveTotalDuration();
  4855. }
  4856. void MythPlayer::ResetTotalDuration(void)
  4857. {
  4858. if (!m_decoder)
  4859. return;
  4860. m_decoder->ResetTotalDuration();
  4861. }
  4862. void MythPlayer::SaveTotalFrames(void)
  4863. {
  4864. if (!m_decoder)
  4865. return;
  4866. m_decoder->SaveTotalFrames();
  4867. }
  4868. void MythPlayer::syncWithAudioStretch()
  4869. {
  4870. if (m_decoder && m_audio.HasAudioOut())
  4871. {
  4872. float stretch = m_audio.GetStretchFactor();
  4873. m_disablePassthrough |= (stretch < 0.99F) || (stretch > 1.01F);
  4874. LOG(VB_PLAYBACK, LOG_INFO, LOC +
  4875. QString("Stretch Factor %1, %2 passthru ")
  4876. .arg(m_audio.GetStretchFactor())
  4877. .arg((m_disablePassthrough) ? "disable" : "allow"));
  4878. SetDisablePassThrough(m_disablePassthrough);
  4879. }
  4880. }
  4881. void MythPlayer::SetDisablePassThrough(bool disabled)
  4882. {
  4883. if (m_decoder && m_audio.HasAudioOut())
  4884. {
  4885. m_decoder->SetDisablePassThrough(m_disablePassthrough || disabled);
  4886. }
  4887. }
  4888. void MythPlayer::ForceSetupAudioStream(void)
  4889. {
  4890. if (m_decoder && m_audio.HasAudioOut())
  4891. {
  4892. m_decoder->ForceSetupAudioStream();
  4893. }
  4894. }
  4895. static unsigned dbg_ident(const MythPlayer *player)
  4896. {
  4897. static QMutex s_dbgLock;
  4898. static unsigned s_dbgNextIdent = 0;
  4899. using DbgMapType = QMap<const MythPlayer*, unsigned>;
  4900. static DbgMapType s_dbgIdent;
  4901. QMutexLocker locker(&s_dbgLock);
  4902. DbgMapType::iterator it = s_dbgIdent.find(player);
  4903. if (it != s_dbgIdent.end())
  4904. return *it;
  4905. return s_dbgIdent[player] = s_dbgNextIdent++;
  4906. }
  4907. /* vim: set expandtab tabstop=4 shiftwidth=4: */