MythTV  master
tv_rec.cpp
Go to the documentation of this file.
1 // C headers
2 #include <chrono> // for milliseconds
3 #include <cstdio>
4 #include <cstdlib>
5 #include <cstring>
6 #include <sched.h> // for sched_yield
7 #include <thread> // for sleep_for
8 #include <utility>
9 
10 // MythTV headers
11 
12 #include "libmyth/programinfo.h"
13 #include "libmyth/remoteutil.h"
14 #include "libmythbase/compat.h"
15 #include "libmythbase/mythconfig.h"
17 #include "libmythbase/mythdate.h"
18 #include "libmythbase/mythdb.h"
20 #include "libmythbase/mythrandom.h"
22 
23 #include "cardutil.h"
24 #include "channelgroup.h"
25 #include "eitscanner.h"
26 #include "io/mythmediabuffer.h"
27 #include "jobqueue.h"
28 #include "livetvchain.h"
29 #include "mpeg/atscstreamdata.h"
30 #include "mpeg/atsctables.h"
31 #include "mpeg/dvbstreamdata.h"
32 #include "mythsystemevent.h"
33 #include "osd.h"
34 #include "previewgeneratorqueue.h"
35 #include "recorders/channelbase.h"
36 #include "recorders/dtvchannel.h"
37 #include "recorders/dtvrecorder.h"
39 #include "recorders/v4lchannel.h"
40 #include "recorders/vboxutils.h"
41 #include "recordingprofile.h"
42 #include "recordingrule.h"
43 #include "tv_rec.h"
44 #include "tvremoteutil.h"
45 
46 #define DEBUG_CHANNEL_PREFIX 0
48 #define LOC QString("TVRec[%1]: ").arg(m_inputId)
49 #define LOC2 QString("TVRec[%1]: ").arg(inputid) // for static functions
50 
51 QReadWriteLock TVRec::s_inputsLock;
52 QMap<uint,TVRec*> TVRec::s_inputs;
53 
54 static bool is_dishnet_eit(uint inputid);
55 static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
56  bool on_host, bool transcode_bfr_comm, bool on_line_comm);
58 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout);
59 
84 TVRec::TVRec(int inputid)
85  // Various threads
86  : m_eventThread(new MThread("TVRecEvent", this)),
87  // Configuration variables from setup routines
88  m_inputId(inputid)
89 {
90  s_inputs[m_inputId] = this;
91 }
92 
93 bool TVRec::CreateChannel(const QString &startchannel,
94  bool enter_power_save_mode)
95 {
96  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("CreateChannel(%1)")
97  .arg(startchannel));
98  // If this recorder is a child and its parent is not in error, we
99  // do not need nor want to set the channel.
100  bool setchan = true;
101  if (m_parentId)
102  {
103  TVRec *parentTV = GetTVRec(m_parentId);
104  if (parentTV && parentTV->GetState() != kState_Error)
105  setchan = false;
106  }
108  this, m_genOpt, m_dvbOpt, m_fwOpt,
109  startchannel, enter_power_save_mode, m_rbFileExt, setchan);
110 
111 #ifdef USING_VBOX
112  if (m_genOpt.m_inputType == "VBOX")
113  {
114  if (!CardUtil::IsVBoxPresent(m_inputId))
115  {
116  // VBOX presence failed, recorder is marked errored
117  LOG(VB_GENERAL, LOG_ERR, LOC +
118  QString("CreateChannel(%1) failed due to VBOX not responding "
119  "to network check on inputid [%2]")
120  .arg(startchannel).arg(m_inputId));
121  m_channel = nullptr;
122  }
123  }
124 #endif
125 
126 #ifdef USING_SATIP
127  if (m_genOpt.m_inputType == "SATIP")
128  {
129  if (!CardUtil::IsSatIPPresent(m_inputId))
130  {
131  // SatIP box presence failed, recorder is marked errored
132  LOG(VB_GENERAL, LOG_ERR, LOC +
133  QString("CreateChannel(%1) failed due to SatIP box not responding "
134  "to network check on inputid [%2]")
135  .arg(startchannel).arg(m_inputId));
136  m_channel = nullptr;
137  }
138  }
139 #endif
140 
141  if (!m_channel)
142  {
143  SetFlags(kFlagErrored, __FILE__, __LINE__);
144  return false;
145  }
146 
147  return true;
148 }
149 
155 bool TVRec::Init(void)
156 {
157  QMutexLocker lock(&m_stateChangeLock);
158 
160  return false;
161 
163 
164  // configure the Channel instance
165  QString startchannel = CardUtil::GetStartChannel(m_inputId);
166  if (startchannel.isEmpty())
167  return false;
168  if (!CreateChannel(startchannel, true))
169  return false;
170 
172  gCoreContext->GetBoolSetting("AutoTranscodeBeforeAutoCommflag", false);
173  m_earlyCommFlag = gCoreContext->GetBoolSetting("AutoCommflagWhileRecording", false);
174  m_runJobOnHostOnly = gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false);
175  m_eitTransportTimeout = gCoreContext->GetDurSetting<std::chrono::minutes>("EITTransportTimeout", 5min);
176  if (m_eitTransportTimeout < 6s)
178  m_eitCrawlIdleStart = gCoreContext->GetDurSetting<std::chrono::seconds>("EITCrawIdleStart", 60s);
179  m_audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
180  m_overRecordSecNrml = gCoreContext->GetDurSetting<std::chrono::seconds>("RecordOverTime");
181  m_overRecordSecCat = gCoreContext->GetDurSetting<std::chrono::minutes>("CategoryOverTime");
182  m_overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
183 
184  m_eventThread->start();
185 
187 
188  return true;
189 }
190 
196 {
197  s_inputs.remove(m_inputId);
198 
200  {
201  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
202  m_eventThread->wait();
203  delete m_eventThread;
204  m_eventThread = nullptr;
205  }
206 
207  if (m_channel)
208  {
209  delete m_channel;
210  m_channel = nullptr;
211  }
212 }
213 
215 {
216  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownAll");
217 
219 
220  if (m_scanner)
221  {
222  delete m_scanner;
223  m_scanner = nullptr;
224  }
225 
227 
228  SetRingBuffer(nullptr);
229 }
230 
232 {
233  QMutexLocker locker(&m_triggerEventLoopLock);
235  m_triggerEventLoopWait.wakeAll();
236 }
237 
245 {
246  if (m_changeState)
247  return kState_ChangingState;
248  return m_internalState;
249 }
250 
259 {
260  QMutexLocker lock(&m_stateChangeLock);
261 
262  ProgramInfo *tmppginfo = nullptr;
263 
265  {
266  tmppginfo = new ProgramInfo(*m_curRecording);
268  }
269  else
270  tmppginfo = new ProgramInfo();
271  tmppginfo->SetInputID(m_inputId);
272 
273  return tmppginfo;
274 }
275 
290 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
291  bool hasLater)
292 {
293  QMutexLocker statelock(&m_stateChangeLock);
294  QMutexLocker pendlock(&m_pendingRecLock);
295 
296  if (secsleft < 0s)
297  {
298  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
299  QString("inputid [%1]").arg(rcinfo->GetInputID()));
300 
301  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
302  if (it != m_pendingRecordings.end())
303  {
304  (*it).m_ask = false;
305  (*it).m_doNotAsk = (*it).m_canceled = true;
306  }
307  return;
308  }
309 
310  LOG(VB_RECORD, LOG_INFO, LOC +
311  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
312 
313  PendingInfo pending;
314  pending.m_info = new ProgramInfo(*rcinfo);
315  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
316  pending.m_hasLaterShowing = hasLater;
317  pending.m_ask = true;
318  pending.m_doNotAsk = false;
319 
320  m_pendingRecordings[rcinfo->GetInputID()] = pending;
321 
322  // If this isn't a recording for this instance to make, we are done
323  if (rcinfo->GetInputID() != m_inputId)
324  return;
325 
326  // We also need to check our input groups
327  std::vector<unsigned int> inputids = CardUtil::GetConflictingInputs(rcinfo->GetInputID());
328 
329  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
330 
331  pendlock.unlock();
332  statelock.unlock();
333  for (uint inputid : inputids)
334  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
335  statelock.relock();
336  pendlock.relock();
337 }
338 
343 {
346  delete old_rec;
347 }
348 
352 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
353 {
354  bool spcat = (!m_overRecordCategory.isEmpty() &&
356  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
357  return pi->GetRecordingEndTime().addSecs(secs.count());
358 }
359 
365 void TVRec::CancelNextRecording(bool cancel)
366 {
367  QMutexLocker pendlock(&m_pendingRecLock);
368  LOG(VB_RECORD, LOG_INFO, LOC +
369  QString("CancelNextRecording(%1) -- begin").arg(cancel));
370 
371  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
372  if (it == m_pendingRecordings.end())
373  {
374  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
375  "error, unknown recording").arg(cancel));
376  return;
377  }
378 
379  if (cancel)
380  {
381  std::vector<unsigned int> &inputids = (*it).m_possibleConflicts;
382  for (uint inputid : inputids)
383  {
384  LOG(VB_RECORD, LOG_INFO, LOC +
385  QString("CancelNextRecording -- inputid 0x%1")
386  .arg((uint64_t)inputid,0,16));
387 
388  pendlock.unlock();
389  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
390  pendlock.relock();
391  }
392 
393  LOG(VB_RECORD, LOG_INFO, LOC +
394  QString("CancelNextRecording -- inputid [%1]")
395  .arg(m_inputId));
396 
397  RecordPending((*it).m_info, -1s, false);
398  }
399  else
400  {
401  (*it).m_canceled = false;
402  }
403 
404  LOG(VB_RECORD, LOG_INFO, LOC +
405  QString("CancelNextRecording(%1) -- end").arg(cancel));
406 }
407 
416 {
417  RecordingInfo ri1(*pginfo);
420  RecordingInfo *rcinfo = &ri1;
421 
422  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
423  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
424 
425  QMutexLocker lock(&m_stateChangeLock);
426 
429 
430  // Flush out any pending state changes
432 
433  // We need to do this check early so we don't cancel an overrecord
434  // that we're trying to extend.
438  {
439  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
440  .secsTo(m_recordEndTime);
441 
446 
448  .addSecs(post_roll_seconds);
449 
450  QString msg = QString("updating recording: %1 %2 %3 %4")
451  .arg(m_curRecording->GetTitle(),
452  QString::number(m_curRecording->GetChanID()),
455  LOG(VB_RECORD, LOG_INFO, LOC + msg);
456 
457  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
458 
460  return RecStatus::Recording;
461  }
462 
463  bool cancelNext = false;
464  PendingInfo pendinfo;
465  PendingMap::iterator it;
466 
467  m_pendingRecLock.lock();
468  if ((it = m_pendingRecordings.find(m_inputId)) != m_pendingRecordings.end())
469  {
470  (*it).m_ask = (*it).m_doNotAsk = false;
471  cancelNext = (*it).m_canceled;
472  }
473  m_pendingRecLock.unlock();
474 
475  // Flush out events...
477 
478  // Rescan pending recordings since the event loop may have deleted
479  // a stale entry. If this happens the info pointer will not be valid
480  // since the HandlePendingRecordings loop will have deleted it.
481  m_pendingRecLock.lock();
482  it = m_pendingRecordings.find(m_inputId);
483  bool has_pending = (it != m_pendingRecordings.end());
484  if (has_pending)
485  pendinfo = *it;
486  m_pendingRecLock.unlock();
487 
488  // If the needed input is in a shared input group, and we are
489  // not canceling the recording anyway, check other recorders
490  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
491  {
492  LOG(VB_RECORD, LOG_INFO, LOC +
493  "Checking input group recorders - begin");
494  std::vector<unsigned int> &inputids = pendinfo.m_possibleConflicts;
495 
496  uint mplexid = 0;
497  uint chanid = 0;
498  uint sourceid = 0;
499  std::vector<unsigned int> inputids2;
500  std::vector<TVState> states;
501 
502  // Stop remote recordings if needed
503  for (uint inputid : inputids)
504  {
505  InputInfo busy_input;
506  bool is_busy = RemoteIsBusy(inputid, busy_input);
507 
508  if (is_busy && !sourceid)
509  {
510  mplexid = pendinfo.m_info->QueryMplexID();
511  chanid = pendinfo.m_info->GetChanID();
512  sourceid = pendinfo.m_info->GetSourceID();
513  }
514 
515  if (is_busy &&
516  ((sourceid != busy_input.m_sourceId) ||
517  (mplexid != busy_input.m_mplexId) ||
518  ((mplexid == 0 || mplexid == 32767) &&
519  chanid != busy_input.m_chanId)))
520  {
521  states.push_back((TVState) RemoteGetState(inputid));
522  inputids2.push_back(inputid);
523  }
524  }
525 
526  bool ok = true;
527  for (uint i = 0; (i < inputids2.size()) && ok; i++)
528  {
529  LOG(VB_RECORD, LOG_INFO, LOC +
530  QString("Attempting to stop input [%1] in state %2")
531  .arg(inputids2[i]).arg(StateToString(states[i])));
532 
533  bool success = RemoteStopRecording(inputids2[i]);
534  if (success)
535  {
536  uint state = RemoteGetState(inputids2[i]);
537  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
538  .arg(inputids2[i]).arg(StateToString((TVState)state)));
539  success = (kState_None == state);
540  }
541 
542  // If we managed to stop LiveTV recording, restart playback..
543  if (success && states[i] == kState_WatchingLiveTV)
544  {
545  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
546  MythEvent me(message);
547  gCoreContext->dispatch(me);
548  }
549 
550  LOG(VB_RECORD, LOG_INFO, LOC +
551  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
552  .arg(success ? "succeeded" : "failed"));
553 
554  ok &= success;
555  }
556 
557  // If we failed to stop the remote recordings, don't record
558  if (!ok)
559  {
560  CancelNextRecording(true);
561  cancelNext = true;
562  }
563 
564  inputids.clear();
565 
566  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
567  }
568 
569  bool did_switch = false;
570  if (!cancelNext && (GetState() == kState_RecordingOnly))
571  {
573  did_switch = (nullptr != ri2);
574  if (did_switch)
575  {
576  // Make sure scheduler is allowed to end this recording
577  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
578 
580  }
581  else
582  {
583  // If in post-roll, end recording
584  m_stateChangeLock.unlock();
585  StopRecording();
586  m_stateChangeLock.lock();
587  }
588  }
589 
590  if (!cancelNext && (GetState() == kState_None))
591  {
592  if (m_tvChain)
593  {
594  QString message = QString("LIVETV_EXITED");
595  MythEvent me(message, m_tvChain->GetID());
596  gCoreContext->dispatch(me);
597  m_tvChain->DecrRef();
598  m_tvChain = nullptr;
599  }
600 
602 
603  // Tell event loop to begin recording.
604  m_curRecording = new RecordingInfo(*rcinfo);
609 
610  // Make sure scheduler is allowed to end this recording
611  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
612 
615  else
616  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
618  }
619  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
620  {
624 
625  // We want the frontend to change channel for recording
626  // and disable the UI for channel change, PiP, etc.
627 
628  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
629  QStringList prog;
630  rcinfo->ToStringList(prog);
631  MythEvent me(message, prog);
632  gCoreContext->dispatch(me);
633  }
634  else if (!did_switch)
635  {
636  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
637  .arg(rcinfo->GetTitle(),
638  QString::number(rcinfo->GetChanID()),
641 
642  if (cancelNext)
643  {
644  msg += "But a user has canceled this recording";
646  }
647  else
648  {
649  msg += QString("But the current state is: %1")
652  }
653 
655  {
656  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
657  .arg(m_curRecording->GetTitle(),
658  QString::number(m_curRecording->GetChanID()),
661  }
662 
663  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
664  }
665 
666  for (const auto & pend : qAsConst(m_pendingRecordings))
667  delete pend.m_info;
668  m_pendingRecordings.clear();
669 
670  if (!did_switch)
671  {
673 
674  QMutexLocker locker(&m_pendingRecLock);
675  if ((m_curRecording) &&
680  {
681  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
682  }
683  return m_recStatus;
684  }
685 
686  return GetRecordingStatus();
687 }
688 
690 {
691  QMutexLocker pendlock(&m_pendingRecLock);
692  return m_recStatus;
693 }
694 
696  RecStatus::Type new_status, int line, bool have_lock)
697 {
698  RecStatus::Type old_status { RecStatus::Unknown };
699  if (have_lock)
700  {
701  old_status = m_recStatus;
702  m_recStatus = new_status;
703  }
704  else
705  {
706  m_pendingRecLock.lock();
707  old_status = m_recStatus;
708  m_recStatus = new_status;
709  m_pendingRecLock.unlock();
710  }
711 
712  LOG(VB_RECORD, LOG_INFO, LOC +
713  QString("SetRecordingStatus(%1->%2) on line %3")
714  .arg(RecStatus::toString(old_status, kSingleRecord),
715  RecStatus::toString(new_status, kSingleRecord),
716  QString::number(line)));
717 }
718 
725 void TVRec::StopRecording(bool killFile)
726 {
727  if (StateIsRecording(GetState()))
728  {
729  QMutexLocker lock(&m_stateChangeLock);
730  if (killFile)
731  SetFlags(kFlagKillRec, __FILE__, __LINE__);
732  else if (m_curRecording)
733  {
734  QDateTime now = MythDate::current(true);
735  if (now < m_curRecording->GetDesiredEndTime())
737  }
739  // wait for state change to take effect
741  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
742 
744  }
745 }
746 
753 {
754  return (state == kState_RecordingOnly ||
755  state == kState_WatchingLiveTV);
756 }
757 
763 {
764  return (state == kState_WatchingPreRecorded);
765 }
766 
773 {
774  if (StateIsRecording(state))
775  return kState_None;
776 
777  LOG(VB_GENERAL, LOG_ERR, LOC +
778  QString("Unknown state in RemoveRecording: %1")
779  .arg(StateToString(state)));
780  return kState_Error;
781 }
782 
789 {
790  if (StateIsPlaying(state))
791  {
792  if (state == kState_WatchingPreRecorded)
793  return kState_None;
794  return kState_RecordingOnly;
795  }
796 
797  QString msg = "Unknown state in RemovePlaying: %1";
798  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
799 
800  return kState_Error;
801 }
802 
809 {
810  if (!curRec)
811  return;
812 
813  curRec->StartedRecording(m_rbFileExt);
814  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
815  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
816 
817  if (curRec->IsCommercialFree())
819 
820  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
822  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
823 
824  SendMythSystemRecEvent("REC_STARTED", curRec);
825 }
826 
835 {
836  if (!curRec)
837  return;
838 
839  // Make sure the recording group is up to date
840  const QString recgrp = curRec->QueryRecordingGroup();
841  curRec->SetRecordingGroup(recgrp);
842 
843  bool is_good = true;
844  if (recq)
845  {
846  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
847  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
848  .arg(curRec->MakeUniqueKey(),
849  (recq->IsDamaged()) ? "damaged" : "good",
850  recq->toStringXML()));
851  is_good = !recq->IsDamaged();
852  delete recq;
853  recq = nullptr;
854  }
855 
856  RecStatus::Type ors = curRec->GetRecordingStatus();
857  // Set the final recording status
858  if (curRec->GetRecordingStatus() == RecStatus::Recording)
860  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
862  curRec->SetRecordingEndTime(MythDate::current(true));
863  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
864 
865  // Figure out if this was already done for this recording
866  bool was_finished = false;
867  static QMutex s_finRecLock;
868  static QHash<QString,QDateTime> s_finRecMap;
869  {
870  QMutexLocker locker(&s_finRecLock);
871  QDateTime now = MythDate::current();
872  QDateTime expired = now.addSecs(-60*5);
873  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
874  while (it != s_finRecMap.end())
875  {
876  if ((*it) < expired)
877  it = s_finRecMap.erase(it);
878  else
879  ++it;
880  }
881  QString key = curRec->MakeUniqueKey();
882  it = s_finRecMap.find(key);
883  if (it != s_finRecMap.end())
884  was_finished = true;
885  else
886  s_finRecMap[key] = now;
887  }
888 
889  // Print something informative to the log
890  LOG(VB_RECORD, LOG_INFO, LOC +
891  QString("FinishedRecording(%1) %2 quality"
892  "\n\t\t\ttitle: %3\n\t\t\t"
893  "in recgroup: %4 status: %5:%6 %7 %8")
894  .arg(curRec->MakeUniqueKey(),
895  is_good ? "Good" : "Bad",
896  curRec->GetTitle(),
897  recgrp,
900  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
901  was_finished?"already_finished":"finished_now"));
902 
903  // This has already been called on this recording..
904  if (was_finished)
905  return;
906 
907  // Notify the frontend watching live tv that this file is final
908  if (m_tvChain)
909  m_tvChain->FinishedRecording(curRec);
910 
911  // if this is a dummy recorder, do no more..
913  {
914  curRec->FinishedRecording(true); // so end time is updated
915  SendMythSystemRecEvent("REC_FINISHED", curRec);
916  return;
917  }
918 
919  // Get the width and set the videoprops
920  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
921  uint avg_height = curRec->QueryAverageHeight();
922  bool progressive = curRec->QueryAverageScanProgressive();
923  curRec->SaveVideoProperties
924  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
925  VID_WIDESCREEN | VID_PROGRESSIVE,
926  ((avg_height > 2000) ? VID_4K :
927  ((avg_height > 1000) ? VID_1080 :
928  ((avg_height > 700) ? VID_720 : 0))) |
929  (progressive ? VID_PROGRESSIVE : 0) |
930  ((is_good) ? 0 : VID_DAMAGED) |
931  (((aspectRatio == MARK_ASPECT_16_9) ||
932  (aspectRatio == MARK_ASPECT_2_21_1)) ? VID_WIDESCREEN : 0));
933 
934  // Make sure really short recordings have positive run time.
935  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
936  {
937  curRec->SetRecordingEndTime(
938  curRec->GetRecordingStartTime().addSecs(60));
939  }
940 
941  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
942  // so that it contains the final filesize information
943  if (!curRec->GetRecordingFile())
944  curRec->LoadRecordingFile();
945 
946  // Generate a preview
947  uint64_t fsize = curRec->GetFilesize();
948  if (curRec->IsLocal() && (fsize >= 1000) &&
950  {
952  }
953 
954  // store recording in recorded table
955  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
956 
957  // send out UPDATE_RECORDING_STATUS message
958  if (recgrp != "LiveTV")
959  {
960  LOG(VB_RECORD, LOG_INFO, LOC +
961  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
962  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
964  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
965  .arg(curRec->GetInputID())
966  .arg(curRec->GetChanID())
968  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
969  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
970  gCoreContext->dispatch(me);
971  }
972 
973  // send out REC_FINISHED message
974  SendMythSystemRecEvent("REC_FINISHED", curRec);
975 
976  // send out DONE_RECORDING message
977  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
978  QString message = QString("DONE_RECORDING %1 %2 %3")
979  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
980  MythEvent me(message);
981  gCoreContext->dispatch(me);
982 
983  // Handle JobQueue
984  QHash<QString,int>::iterator autoJob =
985  m_autoRunJobs.find(curRec->MakeUniqueKey());
986  if (autoJob == m_autoRunJobs.end())
987  {
988  LOG(VB_GENERAL, LOG_INFO,
989  "autoRunJobs not initialized until FinishedRecording()");
991  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
992  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
993  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
994  }
995  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
996  if ((recgrp == "LiveTV") || (fsize < 1000) ||
997  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
998  (curRec->GetRecordingStartTime().secsTo(
999  MythDate::current()) < 120))
1000  {
1003  }
1004  if (*autoJob != JOB_NONE)
1005  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
1006  m_autoRunJobs.erase(autoJob);
1007 }
1008 
1009 #define TRANSITION(ASTATE,BSTATE) \
1010  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
1011 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
1012 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
1013 
1022 {
1023  TVState nextState = m_internalState;
1024 
1025  bool changed = false;
1026 
1027  QString transMsg = QString(" %1 to %2")
1028  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1029 
1031  {
1032  LOG(VB_GENERAL, LOG_ERR, LOC +
1033  "HandleStateChange(): Null transition" + transMsg);
1034  m_changeState = false;
1035  return;
1036  }
1037 
1038  // Make sure EIT scan is stopped before any tuning,
1039  // to avoid race condition with it's tuning requests.
1041  {
1042  LOG(VB_EIT, LOG_INFO, LOC + QString("Stop EIT scan on input %1").arg(GetInputId()));
1043 
1045  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1047  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1048  }
1049 
1050  // Handle different state transitions
1052  {
1054  SET_NEXT();
1055  }
1057  {
1059  SET_NEXT();
1060  }
1062  {
1063  SetPseudoLiveTVRecording(nullptr);
1064 
1065  SET_NEXT();
1066  }
1068  {
1069  SetPseudoLiveTVRecording(nullptr);
1071  SET_NEXT();
1072  }
1074  {
1077  (GetFlags()&kFlagKillRec)));
1078  SET_NEXT();
1079  }
1080 
1081  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1082  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1083 
1084  // update internal state variable
1085  m_internalState = nextState;
1086  m_changeState = false;
1087 
1090  {
1092  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1093  }
1094  else
1095  {
1096  m_eitScanStartTime = m_eitScanStartTime.addYears(1);
1097  }
1098 }
1099 #undef TRANSITION
1100 #undef SET_NEXT
1101 #undef SET_LAST
1102 
1107 {
1108  QMutexLocker lock(&m_stateChangeLock);
1109  m_desiredNextState = nextState;
1110  m_changeState = true;
1111  WakeEventLoop();
1112 }
1113 
1128 void TVRec::TeardownRecorder(uint request_flags)
1129 {
1130  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1131  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1132 
1133  m_pauseNotify = false;
1134  m_isPip = false;
1135 
1137  {
1140  delete m_recorderThread;
1141  m_recorderThread = nullptr;
1142  }
1144  __FILE__, __LINE__);
1145 
1146  RecordingQuality *recq = nullptr;
1147  if (m_recorder)
1148  {
1149  if (GetV4LChannel())
1150  m_channel->SetFd(-1);
1151 
1153 
1154  QMutexLocker locker(&m_stateChangeLock);
1155  delete m_recorder;
1156  m_recorder = nullptr;
1157  }
1158 
1159  if (m_buffer)
1160  {
1161  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1162  m_buffer->StopReads();
1163  }
1164 
1165  if (m_curRecording)
1166  {
1167  if (!!(request_flags & kFlagKillRec))
1169 
1171 
1173  delete m_curRecording;
1174  m_curRecording = nullptr;
1175  }
1176 
1177  m_pauseNotify = true;
1178 
1179  if (GetDTVChannel())
1181 }
1182 
1184 {
1185  return dynamic_cast<DTVRecorder*>(m_recorder);
1186 }
1187 
1189 {
1190  if (m_channel &&
1191  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1192  m_genOpt.m_inputType == "FREEBOX" ||
1193  m_genOpt.m_inputType == "VBOX" ||
1194  m_genOpt.m_inputType == "HDHOMERUN" ||
1195  m_genOpt.m_inputType == "EXTERNAL" ||
1197  {
1198  m_channel->Close();
1199  }
1200 }
1201 
1203 {
1204  return dynamic_cast<DTVChannel*>(m_channel);
1205 }
1206 
1208 {
1209 #ifdef USING_V4L2
1210  return dynamic_cast<V4LChannel*>(m_channel);
1211 #else
1212  return nullptr;
1213 #endif // USING_V4L2
1214 }
1215 
1216 static bool get_use_eit(uint inputid)
1217 {
1218  MSqlQuery query(MSqlQuery::InitCon());
1219  query.prepare(
1220  "SELECT SUM(useeit) "
1221  "FROM videosource, capturecard "
1222  "WHERE videosource.sourceid = capturecard.sourceid AND"
1223  " capturecard.cardid = :INPUTID");
1224  query.bindValue(":INPUTID", inputid);
1225 
1226  if (!query.exec() || !query.isActive())
1227  {
1228  MythDB::DBError("get_use_eit", query);
1229  return false;
1230  }
1231  if (query.next())
1232  return query.value(0).toBool();
1233  return false;
1234 }
1235 
1236 static bool is_dishnet_eit(uint inputid)
1237 {
1238  MSqlQuery query(MSqlQuery::InitCon());
1239  query.prepare(
1240  "SELECT SUM(dishnet_eit) "
1241  "FROM videosource, capturecard "
1242  "WHERE videosource.sourceid = capturecard.sourceid AND"
1243  " capturecard.cardid = :INPUTID");
1244  query.bindValue(":INPUTID", inputid);
1245 
1246  if (!query.exec() || !query.isActive())
1247  {
1248  MythDB::DBError("is_dishnet_eit", query);
1249  return false;
1250  }
1251  if (query.next())
1252  return query.value(0).toBool();
1253  return false;
1254 }
1255 
1256 // Highest capturecard instance number including multirec instances
1257 static int get_highest_input(void)
1258 {
1259  MSqlQuery query(MSqlQuery::InitCon());
1260 
1261  QString str =
1262  "SELECT MAX(cardid) "
1263  "FROM capturecard ";
1264 
1265  query.prepare(str);
1266 
1267  if (!query.exec() || !query.isActive())
1268  {
1269  MythDB::DBError("highest_input", query);
1270  return -1;
1271  }
1272  if (query.next())
1273  return query.value(0).toInt();
1274  return -1;
1275 }
1276 
1277 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1278 {
1279  // Randomize start time a bit
1280  auto timeout = std::chrono::seconds(MythRandom(0, eitTransportTimeout.count() / 3));
1281 
1282  // Use the highest input number and the current input number
1283  // to distribute the scan start evenly over eitTransportTimeout
1284  int highest_input = get_highest_input();
1285  if (highest_input > 0)
1286  timeout += eitTransportTimeout * inputId / highest_input;
1287 
1288  return timeout;
1289 }
1290 
1292 void TVRec::run(void)
1293 {
1294  QMutexLocker lock(&m_stateChangeLock);
1295  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1296  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1297 
1299 
1300  // Check whether we should use the EITScanner in this TVRec instance
1301  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1302  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1303  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1304  {
1307  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1308  }
1309  else
1310  {
1311  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1312  }
1313 
1314  while (HasFlags(kFlagRunMainLoop))
1315  {
1316  // If there is a state change queued up, do it...
1317  if (m_changeState)
1318  {
1321  __FILE__, __LINE__);
1322  }
1323 
1324  // Quick exit on fatal errors.
1325  if (IsErrored())
1326  {
1327  LOG(VB_GENERAL, LOG_ERR, LOC +
1328  "RunTV encountered fatal error, exiting event thread.");
1329  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1330  TeardownAll();
1331  return;
1332  }
1333 
1334  // Handle any tuning events.. Blindly grabbing the lock here
1335  // can sometimes cause a deadlock with Init() while it waits
1336  // to make sure this thread starts. Until a better solution
1337  // is found, don't run HandleTuning unless we can safely get
1338  // the lock.
1339  if (s_inputsLock.tryLockForRead())
1340  {
1341  HandleTuning();
1342  s_inputsLock.unlock();
1343  }
1344 
1345  // Tell frontends about pending recordings
1347 
1348  // If we are recording a program, check if the recording is
1349  // over or someone has asked us to finish the recording.
1350  // Add an extra 60 seconds to the recording end time if we
1351  // might want a back to back recording.
1352  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1353  m_recordEndTime.addSecs(60) : m_recordEndTime;
1354  if ((GetState() == kState_RecordingOnly) &&
1355  (MythDate::current() > recEnd ||
1357  {
1359  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1360  }
1361 
1362  if (m_curRecording)
1363  {
1365 
1366  if (m_recorder)
1367  {
1369 
1370  // Check for recorder errors
1371  if (m_recorder->IsErrored())
1372  {
1374 
1376  {
1377  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1378  MythEvent me(message);
1379  gCoreContext->dispatch(me);
1380  }
1381  else
1383  }
1384  }
1385  }
1386 
1387  // Check for the end of the current program..
1389  {
1390  QDateTime now = MythDate::current();
1391  bool has_finish = HasFlags(kFlagFinishRecording);
1392  bool has_rec = m_pseudoLiveTVRecording;
1393  bool enable_ui = true;
1394 
1395  m_pendingRecLock.lock();
1396  bool rec_soon =
1398  m_pendingRecLock.unlock();
1399 
1400  if (has_rec && (has_finish || (now > m_recordEndTime)))
1401  {
1402  SetPseudoLiveTVRecording(nullptr);
1403  }
1404  else if (!has_rec && !rec_soon && m_curRecording &&
1405  (now >= m_curRecording->GetScheduledEndTime()))
1406  {
1407  if (!m_switchingBuffer)
1408  {
1409  LOG(VB_RECORD, LOG_INFO, LOC +
1410  "Switching Buffer (" +
1411  QString("!has_rec(%1) && ").arg(has_rec) +
1412  QString("!rec_soon(%1) && (").arg(rec_soon) +
1413  MythDate::toString(now, MythDate::ISODate) + " >= " +
1415  QString("(%1) ))")
1416  .arg(now >= m_curRecording->GetScheduledEndTime()));
1417 
1418  m_switchingBuffer = true;
1419 
1421  false, true);
1422  }
1423  else
1424  {
1425  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1426  }
1427  }
1428  else
1429  enable_ui = false;
1430 
1431  if (enable_ui)
1432  {
1433  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1434  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1435  MythEvent me(message);
1436  gCoreContext->dispatch(me);
1437  }
1438  }
1439 
1440  // Check for ExitPlayer flag, and if set change to a non-watching
1441  // state (either kState_RecordingOnly or kState_None).
1443  {
1446  else if (StateIsPlaying(m_internalState))
1448  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1449  }
1450 
1451  // Start active EIT scan
1452  if (m_scanner && m_channel &&
1454  {
1455  if (!m_dvbOpt.m_dvbEitScan)
1456  {
1457  LOG(VB_EIT, LOG_INFO, LOC +
1458  "EIT scanning disabled for this input.");
1459  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1460  }
1461  else if (!get_use_eit(GetInputId()))
1462  {
1463  LOG(VB_EIT, LOG_INFO, LOC +
1464  "EIT scanning disabled for all channels on this input.");
1465  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1466  }
1467  else
1468  {
1469  // Check if another card in the same input group is
1470  // busy. This could be either virtual DVB-devices or
1471  // a second tuner on a single card
1472  s_inputsLock.lockForRead();
1473  bool allow_eit = true;
1474  std::vector<unsigned int> inputids =
1476  InputInfo busy_input;
1477  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1478  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1479  if (allow_eit)
1480  {
1482  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1484  QDateTime::currentDateTime().addYears(1);
1485  }
1486  else
1487  {
1488  LOG(VB_EIT, LOG_INFO, LOC + QString(
1489  "Postponing EIT scan on input [%1] "
1490  "because input %2 is busy")
1491  .arg(m_inputId).arg(busy_input.m_inputId));
1492  m_eitScanStartTime = m_eitScanStartTime.addSecs(300);
1493  }
1494  s_inputsLock.unlock();
1495  }
1496  }
1497 
1498  // We should be no more than a few thousand milliseconds,
1499  // as the end recording code does not have a trigger...
1500  // NOTE: If you change anything here, make sure that
1501  // WaitforEventThreadSleep() will still work...
1502  if (m_tuningRequests.empty() && !m_changeState)
1503  {
1504  lock.unlock(); // stateChangeLock
1505 
1506  {
1507  QMutexLocker locker(&m_triggerEventSleepLock);
1509  m_triggerEventSleepWait.wakeAll();
1510  }
1511 
1512  sched_yield();
1513 
1514  {
1515  QMutexLocker locker(&m_triggerEventLoopLock);
1516  // We check triggerEventLoopSignal because it is possible
1517  // that WakeEventLoop() was called since we
1518  // unlocked the stateChangeLock
1520  {
1522  &m_triggerEventLoopLock, 1000 /* ms */);
1523  }
1524  m_triggerEventLoopSignal = false;
1525  }
1526 
1527  lock.relock(); // stateChangeLock
1528  }
1529  }
1530 
1531  if (GetState() != kState_None)
1532  {
1535  }
1536 
1537  TeardownAll();
1538 }
1539 
1545 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1546 {
1547  bool ok = false;
1548  MythTimer t;
1549  t.start();
1550 
1551  while (!ok && (t.elapsed() < time))
1552  {
1553  MythTimer t2;
1554  t2.start();
1555 
1556  if (wake)
1557  WakeEventLoop();
1558 
1559  m_stateChangeLock.unlock();
1560 
1561  sched_yield();
1562 
1563  {
1564  QMutexLocker locker(&m_triggerEventSleepLock);
1567  m_triggerEventSleepSignal = false;
1568  }
1569 
1570  m_stateChangeLock.lock();
1571 
1572  // verify that we were triggered.
1573  ok = (m_tuningRequests.empty() && !m_changeState);
1574 
1575  std::chrono::milliseconds te = t2.elapsed();
1576  if (!ok && te < 10ms)
1577  std::this_thread::sleep_for(10ms - te);
1578  }
1579  return ok;
1580 }
1581 
1583 {
1584  QMutexLocker pendlock(&m_pendingRecLock);
1585 
1586  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1587  {
1588  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1589  {
1590  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1591  QString("[%1] '%2'")
1592  .arg((*it).m_info->GetInputID())
1593  .arg((*it).m_info->GetTitle()));
1594 
1595  delete (*it).m_info;
1596  it = m_pendingRecordings.erase(it);
1597  }
1598  else
1599  {
1600  it++;
1601  }
1602  }
1603 
1604  if (m_pendingRecordings.empty())
1605  return;
1606 
1607  // Make sure EIT scan is stopped so it does't interfere
1609  {
1610  LOG(VB_CHANNEL, LOG_INFO,
1611  LOC + "Stopping active EIT scan for pending recording.");
1613  }
1614 
1615  // If we have a pending recording and AskAllowRecording
1616  // or DoNotAskAllowRecording is set and the frontend is
1617  // ready send an ASK_RECORDING query to frontend.
1618 
1619  bool has_rec = false;
1620  auto it = m_pendingRecordings.begin();
1621  if ((1 == m_pendingRecordings.size()) &&
1622  (*it).m_ask &&
1623  ((*it).m_info->GetInputID() == m_inputId) &&
1625  {
1627  has_rec = m_pseudoLiveTVRecording &&
1629  (*it).m_recordingStart);
1630  }
1631 
1632  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1633  {
1634  if (!(*it).m_ask && !(*it).m_doNotAsk)
1635  continue;
1636 
1637  auto timeuntil = ((*it).m_doNotAsk) ?
1638  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1639 
1640  if (has_rec)
1641  (*it).m_canceled = true;
1642 
1643  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1644  .arg(m_inputId)
1645  .arg(timeuntil.count())
1646  .arg(has_rec ? 1 : 0)
1647  .arg((*it).m_hasLaterShowing ? 1 : 0);
1648 
1649  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1650 
1651  QStringList msg;
1652  (*it).m_info->ToStringList(msg);
1653  MythEvent me(query, msg);
1654  gCoreContext->dispatch(me);
1655 
1656  (*it).m_ask = (*it).m_doNotAsk = false;
1657  }
1658 }
1659 
1661  uint &parentid,
1662  GeneralDBOptions &gen_opts,
1663  DVBDBOptions &dvb_opts,
1664  FireWireDBOptions &firewire_opts)
1665 {
1666  int testnum = 0;
1667  QString test;
1668 
1669  MSqlQuery query(MSqlQuery::InitCon());
1670  query.prepare(
1671  "SELECT videodevice, vbidevice, audiodevice, "
1672  " audioratelimit, cardtype, "
1673  " skipbtaudio, signal_timeout, channel_timeout, "
1674  " dvb_wait_for_seqstart, "
1675  ""
1676  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1677  ""
1678  " firewire_speed, firewire_model, firewire_connection, "
1679  " parentid "
1680  ""
1681  "FROM capturecard "
1682  "WHERE cardid = :INPUTID");
1683  query.bindValue(":INPUTID", inputid);
1684 
1685  if (!query.exec() || !query.isActive())
1686  {
1687  MythDB::DBError("getdevices", query);
1688  return false;
1689  }
1690 
1691  if (!query.next())
1692  return false;
1693 
1694  // General options
1695  test = query.value(0).toString();
1696  if (!test.isEmpty())
1697  gen_opts.m_videoDev = test;
1698 
1699  test = query.value(1).toString();
1700  if (!test.isEmpty())
1701  gen_opts.m_vbiDev = test;
1702 
1703  test = query.value(2).toString();
1704  if (!test.isEmpty())
1705  gen_opts.m_audioDev = test;
1706 
1707  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1708 
1709  test = query.value(4).toString();
1710  if (!test.isEmpty())
1711  gen_opts.m_inputType = test;
1712 
1713  gen_opts.m_skipBtAudio = query.value(5).toBool();
1714 
1715  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1716  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1717 
1718  // We should have at least 1000 ms to acquire tables...
1719  int table_timeout = ((int)gen_opts.m_channelTimeout -
1720  (int)gen_opts.m_signalTimeout);
1721  if (table_timeout < 1000)
1722  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1723 
1724  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1725 
1726  // DVB options
1727  uint dvboff = 9;
1728  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1729  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1730  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1731 
1732  // Firewire options
1733  uint fireoff = dvboff + 3;
1734  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1735 
1736  test = query.value(fireoff + 1).toString();
1737  if (!test.isEmpty())
1738  firewire_opts.m_model = test;
1739 
1740  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1741 
1742  parentid = query.value(15).toUInt();
1743 
1744  return true;
1745 }
1746 
1747 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1748 {
1749  if (!dtvMon->GetATSCStreamData())
1750  return;
1751 
1752  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1753  if (!mgt)
1754  return;
1755 
1756  for (uint i = 0; i < mgt->TableCount(); ++i)
1757  {
1758  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1759  pid_cache.push_back(item);
1760  }
1761  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1762 }
1763 
1764 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1765 {
1766  pid_cache_t pid_cache;
1767  channel->GetCachedPids(pid_cache);
1768  bool vctpid_cached = false;
1769  for (auto pid : pid_cache)
1770  {
1771  if ((pid.GetTableID() == TableID::TVCT) ||
1772  (pid.GetTableID() == TableID::CVCT))
1773  {
1774  vctpid_cached = true;
1775  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1776  }
1777  }
1778  return vctpid_cached;
1779 }
1780 
1797 {
1798  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1799 
1801  DTVChannel *dtvchan = GetDTVChannel();
1802  if (!sm || !dtvchan)
1803  {
1804  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1805  return false;
1806  }
1807 
1808  MPEGStreamData *sd = nullptr;
1809  if (GetDTVRecorder())
1810  {
1811  sd = GetDTVRecorder()->GetStreamData();
1812  sd->SetCaching(true);
1813  }
1814 
1815  QString recording_type = "all";
1819  const StandardSetting *setting = profile.byName("recordingtype");
1820  if (setting)
1821  recording_type = setting->getValue();
1822 
1823  const QString tuningmode = dtvchan->GetTuningMode();
1824 
1825  // Check if this is an ATSC Channel
1826  int major = dtvchan->GetMajorChannel();
1827  int minor = dtvchan->GetMinorChannel();
1828  if ((minor > 0) && (tuningmode == "atsc"))
1829  {
1830  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1831  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1832 
1833  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1834  if (!asd)
1835  {
1836  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1837  sd->SetCaching(true);
1838  if (GetDTVRecorder())
1839  GetDTVRecorder()->SetStreamData(asd);
1840  }
1841 
1842  asd->Reset();
1843  sm->SetStreamData(sd);
1844  sm->SetChannel(major, minor);
1845  sd->SetRecordingType(recording_type);
1846 
1847  // Try to get pid of VCT from cache and
1848  // require MGT if we don't have VCT pid.
1849  if (!ApplyCachedPids(sm, dtvchan))
1851 
1852  LOG(VB_RECORD, LOG_INFO, LOC +
1853  "Successfully set up ATSC table monitoring.");
1854  return true;
1855  }
1856 
1857  // Check if this is an DVB channel
1858  int progNum = dtvchan->GetProgramNumber();
1859  if ((progNum >= 0) && (tuningmode == "dvb") && (m_genOpt.m_inputType != "VBOX"))
1860  {
1861  int netid = dtvchan->GetOriginalNetworkID();
1862  int tsid = dtvchan->GetTransportID();
1863 
1864  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1865  if (!dsd)
1866  {
1867  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1868  sd->SetCaching(true);
1869  if (GetDTVRecorder())
1870  GetDTVRecorder()->SetStreamData(dsd);
1871  }
1872 
1873  LOG(VB_RECORD, LOG_INFO, LOC +
1874  QString("DVB service_id %1 on net_id %2 tsid %3")
1875  .arg(progNum).arg(netid).arg(tsid));
1876 
1878 
1879  dsd->Reset();
1880  sm->SetStreamData(sd);
1881  sm->SetDVBService(netid, tsid, progNum);
1882  sd->SetRecordingType(recording_type);
1883 
1887  sm->SetRotorTarget(1.0F);
1888 
1889  if (EITscan)
1890  {
1892  sm->IgnoreEncrypted(true);
1893  }
1894 
1895  LOG(VB_RECORD, LOG_INFO, LOC +
1896  "Successfully set up DVB table monitoring.");
1897  return true;
1898  }
1899 
1900  // Check if this is an MPEG channel
1901  if (progNum >= 0)
1902  {
1903  if (!sd)
1904  {
1905  sd = new MPEGStreamData(progNum, m_inputId, true);
1906  sd->SetCaching(true);
1907  if (GetDTVRecorder())
1909  }
1910 
1911  QString msg = QString("MPEG program number: %1").arg(progNum);
1912  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1913 
1915 
1916  sd->Reset();
1917  sm->SetStreamData(sd);
1918  sm->SetProgramNumber(progNum);
1919  sd->SetRecordingType(recording_type);
1920 
1924  sm->SetRotorTarget(1.0F);
1925 
1926  if (EITscan)
1927  {
1929  sm->IgnoreEncrypted(true);
1930  }
1931 
1932  LOG(VB_RECORD, LOG_INFO, LOC +
1933  "Successfully set up MPEG table monitoring.");
1934  return true;
1935  }
1936 
1937  // If this is not an ATSC, DVB or MPEG channel then check to make sure
1938  // that we have permanent pidcache entries.
1939  bool ok = false;
1940  if (GetDTVChannel())
1941  {
1942  pid_cache_t pid_cache;
1943  GetDTVChannel()->GetCachedPids(pid_cache);
1944  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
1945  ok |= item->IsPermanent();
1946  }
1947 
1948  if (!ok)
1949  {
1950  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
1951  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
1952  }
1953  else
1954  {
1955  LOG(VB_RECORD, LOG_INFO, LOC +
1956  "Successfully set up raw pid monitoring.");
1957  }
1958 
1959  return ok;
1960 }
1961 
1976 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
1977 {
1978  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
1979  .arg(tablemon).arg(notify));
1980 
1981  // if it already exists, there no need to initialize it
1982  if (m_signalMonitor)
1983  return true;
1984 
1985  // if there is no channel object we can't monitor it
1986  if (!m_channel)
1987  return false;
1988 
1989  // nothing to monitor here either (DummyChannel)
1990  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
1991  return true;
1992 
1993  // make sure statics are initialized
1995 
1998  m_channel, false);
1999 
2000  if (m_signalMonitor)
2001  {
2002  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
2003  // If this is a monitor for Digital TV, initialize table monitors
2004  if (GetDTVSignalMonitor() && tablemon &&
2005  !SetupDTVSignalMonitor(EITscan))
2006  {
2007  LOG(VB_GENERAL, LOG_ERR, LOC +
2008  "Failed to setup digital signal monitoring");
2009 
2010  return false;
2011  }
2012 
2015  kSignalMonitoringRate * 5 :
2018 
2019  // Start the monitoring thread
2021  }
2022 
2023  return true;
2024 }
2025 
2031 {
2032  if (!m_signalMonitor)
2033  return;
2034 
2035  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2036 
2037  // If this is a DTV signal monitor, save any pids we know about.
2039  DTVChannel *dtvChan = GetDTVChannel();
2040  if (dtvMon && dtvChan)
2041  {
2042  pid_cache_t pid_cache;
2043  GetPidsToCache(dtvMon, pid_cache);
2044  if (!pid_cache.empty())
2045  dtvChan->SaveCachedPids(pid_cache);
2046  }
2047 
2048  if (m_signalMonitor)
2049  {
2050  delete m_signalMonitor;
2051  m_signalMonitor = nullptr;
2052  }
2053 
2054  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2055 }
2056 
2068 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2069 {
2070  QString msg = "SetSignalMonitoringRate(%1, %2)";
2071  LOG(VB_RECORD, LOG_INFO, LOC +
2072  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2073 
2074  QMutexLocker lock(&m_stateChangeLock);
2075 
2077  {
2078  LOG(VB_GENERAL, LOG_ERR, LOC +
2079  "Signal Monitoring is notsupported by your hardware.");
2080  return 0ms;
2081  }
2082 
2084  {
2085  LOG(VB_GENERAL, LOG_ERR, LOC +
2086  "Signal can only be monitored in LiveTV Mode.");
2087  return 0ms;
2088  }
2089 
2090  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2091 
2092  TuningRequest req = (rate > 0ms) ?
2095 
2097 
2098  // Wait for RingBuffer reset
2099  while (!HasFlags(kFlagRingBufferReady))
2101  LOG(VB_RECORD, LOG_INFO, LOC +
2102  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2103  return 1ms;
2104 }
2105 
2107 {
2108  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2109 }
2110 
2122 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2123 {
2124  QString msg("");
2125  MSqlQuery query(MSqlQuery::InitCon());
2126 
2127  if (!query.isConnected())
2128  return false;
2129 
2130  query.prepare("SELECT channel.channum, channel.callsign "
2131  "FROM channel "
2132  "WHERE channel.chanid = :CHANID");
2133  query.bindValue(":CHANID", chanid);
2134  if (!query.exec() || !query.next())
2135  {
2136  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2137  return false;
2138  }
2139 
2140  QString channelname = query.value(0).toString();
2141  QString callsign = query.value(1).toString();
2142 
2143  query.prepare(
2144  "SELECT channel.channum "
2145  "FROM channel, capturecard "
2146  "WHERE deleted IS NULL AND "
2147  " ( channel.chanid = :CHANID OR "
2148  " ( channel.channum = :CHANNUM AND "
2149  " channel.callsign = :CALLSIGN ) "
2150  " ) AND "
2151  " channel.sourceid = capturecard.sourceid AND "
2152  " capturecard.cardid = :INPUTID");
2153  query.bindValue(":CHANID", chanid);
2154  query.bindValue(":CHANNUM", channelname);
2155  query.bindValue(":CALLSIGN", callsign);
2156  query.bindValue(":INPUTID", m_inputId);
2157 
2158  if (!query.exec() || !query.isActive())
2159  {
2160  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2161  }
2162  else if (query.size() > 0)
2163  {
2164  msg = "Found channel (%1) on current input[%2].";
2165  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2166  return false;
2167  }
2168 
2169  // We didn't find it on the current input, so now we check other inputs.
2170  query.prepare(
2171  "SELECT channel.channum, capturecard.cardid "
2172  "FROM channel, capturecard "
2173  "WHERE deleted IS NULL AND "
2174  " ( channel.chanid = :CHANID OR "
2175  " ( channel.channum = :CHANNUM AND "
2176  " channel.callsign = :CALLSIGN ) "
2177  " ) AND "
2178  " channel.sourceid = capturecard.sourceid AND "
2179  " capturecard.cardid != :INPUTID");
2180  query.bindValue(":CHANID", chanid);
2181  query.bindValue(":CHANNUM", channelname);
2182  query.bindValue(":CALLSIGN", callsign);
2183  query.bindValue(":INPUTID", m_inputId);
2184 
2185  if (!query.exec() || !query.isActive())
2186  {
2187  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2188  }
2189  else if (query.next())
2190  {
2191  msg = QString("Found channel (%1) on different input(%2).")
2192  .arg(query.value(0).toString(), query.value(1).toString());
2193  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2194  return true;
2195  }
2196 
2197  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2198  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2199  return false;
2200 }
2201 
2212 bool TVRec::CheckChannel(const QString& name) const
2213 {
2214  if (!m_channel)
2215  return false;
2216 
2217  return m_channel->CheckChannel(name);
2218 }
2219 
2223 static QString add_spacer(const QString &channel, const QString &spacer)
2224 {
2225  QString chan = channel;
2226  if ((chan.length() >= 2) && !spacer.isEmpty())
2227  return chan.left(chan.length()-1) + spacer + chan.right(1);
2228  return chan;
2229 }
2230 
2258 bool TVRec::CheckChannelPrefix(const QString &prefix,
2259  uint &complete_valid_channel_on_rec,
2260  bool &is_extra_char_useful,
2261  QString &needed_spacer) const
2262 {
2263 #if DEBUG_CHANNEL_PREFIX
2264  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2265 #endif
2266 
2267  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2268 
2269  MSqlQuery query(MSqlQuery::InitCon());
2270  QString basequery = QString(
2271  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2272  "FROM channel, capturecard "
2273  "WHERE deleted IS NULL AND "
2274  " channel.channum LIKE '%1%' AND "
2275  " channel.sourceid = capturecard.sourceid");
2276 
2277  const std::array<const QString,2> inputquery
2278  {
2279  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2280  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2281  };
2282 
2283  std::vector<unsigned int> fchanid;
2284  std::vector<QString> fchannum;
2285  std::vector<unsigned int> finputid;
2286  std::vector<QString> fspacer;
2287 
2288  for (const auto & str : inputquery)
2289  {
2290  for (const auto & spacer : s_spacers)
2291  {
2292  QString qprefix = add_spacer(
2293  prefix, (spacer == "_") ? "\\_" : spacer);
2294  query.prepare(basequery.arg(qprefix) + str);
2295 
2296  if (!query.exec() || !query.isActive())
2297  {
2298  MythDB::DBError("checkchannel -- locate channum", query);
2299  }
2300  else if (query.size())
2301  {
2302  while (query.next())
2303  {
2304  fchanid.push_back(query.value(0).toUInt());
2305  fchannum.push_back(query.value(1).toString());
2306  finputid.push_back(query.value(2).toUInt());
2307  fspacer.emplace_back(spacer);
2308 #if DEBUG_CHANNEL_PREFIX
2309  LOG(VB_GENERAL, LOG_DEBUG,
2310  QString("(%1,%2) Adding %3 rec %4")
2311  .arg(i).arg(j).arg(query.value(1).toString(),6)
2312  .arg(query.value(2).toUInt()));
2313 #endif
2314  }
2315  }
2316 
2317  if (prefix.length() < 2)
2318  break;
2319  }
2320  }
2321 
2322  // Now process the lists for the info we need...
2323  is_extra_char_useful = false;
2324  complete_valid_channel_on_rec = 0;
2325  needed_spacer.clear();
2326 
2327  if (fchanid.empty())
2328  return false;
2329 
2330  if (fchanid.size() == 1) // Unique channel...
2331  {
2332  needed_spacer = fspacer[0];
2333  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2334 
2335  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2336  is_extra_char_useful = nc;
2337  return true;
2338  }
2339 
2340  // If we get this far there is more than one channel
2341  // sharing the prefix we were given.
2342 
2343  // Is an extra characher useful for disambiguation?
2344  is_extra_char_useful = false;
2345  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2346  {
2347  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2348 #if DEBUG_CHANNEL_PREFIX
2349  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2350  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2351  .arg(is_extra_char_useful));
2352 #endif
2353  }
2354 
2355  // Are any of the channels complete w/o spacer?
2356  // If so set complete_valid_channel_on_rec,
2357  // with a preference for our inputid.
2358  for (size_t i = 0; i < fchannum.size(); i++)
2359  {
2360  if (fchannum[i] == prefix)
2361  {
2362  complete_valid_channel_on_rec = finputid[i];
2363  if (finputid[i] == m_inputId)
2364  break;
2365  }
2366  }
2367 
2368  if (complete_valid_channel_on_rec != 0)
2369  return true;
2370 
2371  // Add a spacer, if one is needed to select a valid channel.
2372  bool spacer_needed = true;
2373  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2374  spacer_needed = !fspacer[i].isEmpty();
2375  if (spacer_needed)
2376  needed_spacer = fspacer[0];
2377 
2378  // If it isn't useful to wait for more characters,
2379  // then try to commit to any true match immediately.
2380  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2381  {
2382  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2383  {
2384  needed_spacer = fspacer[i];
2385  complete_valid_channel_on_rec = finputid[i];
2386  return true;
2387  }
2388  }
2389 
2390  return true;
2391 }
2392 
2394  const QString &channum)
2395 {
2396  if (!m_recorder)
2397  return false;
2398 
2399  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2400  if (!videoFilters.isEmpty())
2401  {
2402  m_recorder->SetVideoFilters(videoFilters);
2403  return true;
2404  }
2405 
2406  return false;
2407 }
2408 
2414 {
2415  return ((m_recorder && m_recorder->IsRecording()) ||
2417 }
2418 
2424 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2425 {
2426  InputInfo dummy;
2427  if (!busy_input)
2428  busy_input = &dummy;
2429 
2430  busy_input->Clear();
2431 
2432  if (!m_channel)
2433  return false;
2434 
2435  if (!m_channel->GetInputID())
2436  return false;
2437 
2438  uint chanid = 0;
2439 
2440  if (GetState() != kState_None)
2441  {
2442  busy_input->m_inputId = m_channel->GetInputID();
2443  chanid = m_channel->GetChanID();
2444  }
2445 
2446  PendingInfo pendinfo;
2447  bool has_pending = false;
2448  {
2449  m_pendingRecLock.lock();
2450  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2451  has_pending = (it != m_pendingRecordings.end());
2452  if (has_pending)
2453  pendinfo = *it;
2454  m_pendingRecLock.unlock();
2455  }
2456 
2457  if (!busy_input->m_inputId && has_pending)
2458  {
2459  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2460 
2461  if (timeLeft <= time_buffer)
2462  {
2463  QString channum;
2464  QString input;
2465  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2466  {
2467  busy_input->m_inputId = m_channel->GetInputID();
2468  chanid = pendinfo.m_info->GetChanID();
2469  }
2470  }
2471  }
2472 
2473  if (busy_input->m_inputId)
2474  {
2475  CardUtil::GetInputInfo(*busy_input);
2476  busy_input->m_chanId = chanid;
2477  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2478  busy_input->m_mplexId =
2479  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2480  }
2481 
2482  return busy_input->m_inputId != 0U;
2483 }
2484 
2485 
2493 {
2494  QMutexLocker lock(&m_stateChangeLock);
2495 
2496  if (m_recorder)
2497  return m_recorder->GetFrameRate();
2498  return -1.0F;
2499 }
2500 
2508 {
2509  QMutexLocker lock(&m_stateChangeLock);
2510 
2511  if (m_recorder)
2512  return m_recorder->GetFramesWritten();
2513  return -1;
2514 }
2515 
2522 long long TVRec::GetFilePosition(void)
2523 {
2524  QMutexLocker lock(&m_stateChangeLock);
2525 
2526  if (m_buffer)
2527  return m_buffer->GetWritePosition();
2528  return -1;
2529 }
2530 
2538 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2539 {
2540  QMutexLocker lock(&m_stateChangeLock);
2541 
2542  if (m_recorder)
2543  return m_recorder->GetKeyframePosition(desired);
2544  return -1;
2545 }
2546 
2556  int64_t start, int64_t end, frm_pos_map_t &map) const
2557 {
2558  QMutexLocker lock(&m_stateChangeLock);
2559 
2560  if (m_recorder)
2561  return m_recorder->GetKeyframePositions(start, end, map);
2562 
2563  return false;
2564 }
2565 
2567  int64_t start, int64_t end, frm_pos_map_t &map) const
2568 {
2569  QMutexLocker lock(&m_stateChangeLock);
2570 
2571  if (m_recorder)
2572  return m_recorder->GetKeyframeDurations(start, end, map);
2573 
2574  return false;
2575 }
2576 
2582 long long TVRec::GetMaxBitrate(void) const
2583 {
2584  long long bitrate = 0;
2585  if (m_genOpt.m_inputType == "MPEG")
2586  { // NOLINT(bugprone-branch-clone)
2587  bitrate = 10080000LL; // use DVD max bit rate
2588  }
2589  else if (m_genOpt.m_inputType == "HDPVR")
2590  {
2591  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2592  }
2594  {
2595  bitrate = 22200000LL; // 1080i
2596  }
2597  else // frame grabber
2598  {
2599  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2600  }
2601 
2602  return bitrate;
2603 }
2604 
2610 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2611 {
2612  QMutexLocker lock(&m_stateChangeLock);
2613 
2614  m_tvChain = newchain;
2615  m_tvChain->IncrRef(); // mark it for TVRec use
2616  m_tvChain->ReloadAll();
2617 
2618  QString hostprefix = MythCoreContext::GenMythURL(
2621 
2622  m_tvChain->SetHostPrefix(hostprefix);
2624 
2625  m_isPip = pip;
2626  m_liveTVStartChannel = std::move(startchan);
2627 
2628  // Change to WatchingLiveTV
2630  // Wait for state change to take effect
2632 
2633  // Make sure StartRecording can't steal our tuner
2634  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2635 }
2636 
2640 QString TVRec::GetChainID(void)
2641 {
2642  if (m_tvChain)
2643  return m_tvChain->GetID();
2644  return "";
2645 }
2646 
2656 {
2657  QMutexLocker lock(&m_stateChangeLock);
2658 
2660  return; // already stopped
2661 
2662  if (!m_curRecording)
2663  return;
2664 
2665  const QString recgrp = m_curRecording->QueryRecordingGroup();
2667 
2668  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2669  {
2670  // User wants this recording to continue
2672  }
2673  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2674  {
2675  // User wants to abandon scheduled recording
2676  SetPseudoLiveTVRecording(nullptr);
2677  }
2678 }
2679 
2690 {
2691  if (!m_channel)
2692  return;
2693 
2694  // Notify scheduler of the recording.
2695  // + set up recording so it can be resumed
2696  rec->SetInputID(m_inputId);
2698 
2699  if (rec->GetRecordingRuleType() == kNotRecording)
2700  {
2703  }
2704 
2705  // + remove any end offset which would mismatch the live session
2706  rec->GetRecordingRule()->m_endOffset = 0;
2707 
2708  // + save RecStatus::Inactive recstatus to so that a reschedule call
2709  // doesn't start recording this on another input before we
2710  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2712  rec->AddHistory(false);
2713 
2714  // + save RecordingRule so that we get a recordid
2715  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2716  rec->GetRecordingRule()->Save(false);
2717 
2718  // + save recordid to recorded entry
2719  rec->ApplyRecordRecID();
2720 
2721  // + set proper recstatus (saved later)
2723 
2724  // + pass proginfo to scheduler and reschedule
2725  QStringList prog;
2726  rec->ToStringList(prog);
2727  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2728  gCoreContext->dispatch(me);
2729 
2730  // Allow scheduler to end this recording before post-roll,
2731  // if it has another recording for this recorder.
2732  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2733 }
2734 
2736  RecordingProfile *recpro, int line)
2737 {
2738  if (kAutoRunProfile == t)
2739  {
2741  if (!recpro)
2742  {
2743  LoadProfile(nullptr, rec, profile);
2744  recpro = &profile;
2745  }
2746  m_autoRunJobs[rec->MakeUniqueKey()] =
2747  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2749  }
2750  else
2751  {
2753  }
2754  LOG(VB_JOBQUEUE, LOG_INFO,
2755  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2756  .arg(rec->MakeUniqueKey()).arg(line)
2757  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2758 }
2759 
2771 void TVRec::SetLiveRecording(int recording)
2772 {
2773  LOG(VB_GENERAL, LOG_INFO, LOC +
2774  QString("SetLiveRecording(%1)").arg(recording));
2775  QMutexLocker locker(&m_stateChangeLock);
2776 
2777  (void) recording;
2778 
2780  bool was_rec = m_pseudoLiveTVRecording;
2782  if (was_rec && !m_pseudoLiveTVRecording)
2783  {
2784  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2785  // cancel -- 'recording' should be 0 or -1
2786  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2787  m_curRecording->SetRecordingGroup("LiveTV");
2788  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2789  }
2790  else if (!was_rec && m_pseudoLiveTVRecording)
2791  {
2792  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2793  // record -- 'recording' should be 1 or -1
2794 
2795  // If the last recording was flagged for keeping
2796  // in the frontend, then add the recording rule
2797  // so that transcode, commfrag, etc can be run.
2800  recstat = m_curRecording->GetRecordingStatus();
2801  m_curRecording->SetRecordingGroup("Default");
2802  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2803  }
2804 
2805  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2806  .arg(m_curRecording->GetInputID())
2807  .arg(m_curRecording->GetChanID())
2809  .arg(recstat)
2811 
2812  gCoreContext->dispatch(me);
2813 }
2814 
2820 {
2821  QMutexLocker lock(&m_stateChangeLock);
2822  LOG(VB_RECORD, LOG_INFO, LOC +
2823  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2824  .arg((uint64_t)m_curRecording,0,16)
2825  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2826 
2828  return;
2829 
2830  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2832 
2833  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2835 
2836  // Figure out next state and if needed recording end time.
2837  TVState next_state = kState_None;
2839  {
2841  next_state = kState_RecordingOnly;
2842  }
2843 
2844  // Change to the appropriate state
2845  ChangeState(next_state);
2846 
2847  // Wait for state change to take effect...
2849 
2850  // We are done with the tvchain...
2851  if (m_tvChain)
2852  {
2853  m_tvChain->DecrRef();
2854  }
2855  m_tvChain = nullptr;
2856 }
2857 
2867 {
2868  QMutexLocker lock(&m_stateChangeLock);
2869 
2870  if (!m_recorder)
2871  {
2872  LOG(VB_GENERAL, LOG_ERR, LOC +
2873  "PauseRecorder() called with no recorder");
2874  return;
2875  }
2876 
2877  m_recorder->Pause();
2878 }
2879 
2886 {
2887  if (m_pauseNotify)
2888  WakeEventLoop();
2889 }
2890 
2894 void TVRec::ToggleChannelFavorite(const QString& changroupname)
2895 {
2896  QMutexLocker lock(&m_stateChangeLock);
2897 
2898  if (!m_channel)
2899  return;
2900 
2901  // Get current channel id...
2902  uint sourceid = m_channel->GetSourceID();
2903  QString channum = m_channel->GetChannelName();
2904  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
2905 
2906  if (!chanid)
2907  {
2908  LOG(VB_GENERAL, LOG_ERR, LOC +
2909  QString("Channel: \'%1\' was not found in the database.\n"
2910  "\t\tMost likely, the 'starting channel' for this "
2911  "Input Connection is invalid.\n"
2912  "\t\tCould not toggle favorite.").arg(channum));
2913  return;
2914  }
2915 
2916  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
2917  if (changrpid <1)
2918  {
2919  LOG(VB_RECORD, LOG_ERR, LOC +
2920  QString("ToggleChannelFavorite: Invalid channel group name %1,")
2921  .arg(changroupname));
2922  }
2923  else
2924  {
2925  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
2926 
2927  if (!result)
2928  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
2929  else
2930  {
2931  LOG(VB_RECORD, LOG_INFO, LOC +
2932  QString("Toggled channel favorite.channum %1, chan group %2")
2933  .arg(channum, changroupname));
2934  }
2935  }
2936 }
2937 
2944 {
2945  QMutexLocker lock(&m_stateChangeLock);
2946  if (!m_channel)
2947  return -1;
2948 
2949  int ret = m_channel->GetPictureAttribute(attr);
2950 
2951  return (ret < 0) ? -1 : ret / 655;
2952 }
2953 
2962  PictureAttribute attr,
2963  bool direction)
2964 {
2965  QMutexLocker lock(&m_stateChangeLock);
2966  if (!m_channel)
2967  return -1;
2968 
2969  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
2970 
2971  return (ret < 0) ? -1 : ret / 655;
2972 }
2973 
2977 QString TVRec::GetInput(void) const
2978 {
2979  if (m_channel)
2980  return m_channel->GetInputName();
2981  return QString();
2982 }
2983 
2988 {
2989  if (m_channel)
2990  return m_channel->GetSourceID();
2991  return 0;
2992 }
2993 
3002 QString TVRec::SetInput(QString input)
3003 {
3004  QMutexLocker lock(&m_stateChangeLock);
3005  QString origIn = input;
3006  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
3007 
3008  if (!m_channel)
3009  {
3010  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
3011  return QString();
3012  }
3013 
3014  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
3015  ") -- end nothing to do");
3016  return input;
3017 }
3018 
3028 void TVRec::SetChannel(const QString& name, uint requestType)
3029 {
3030  QMutexLocker locker1(&m_setChannelLock);
3031  QMutexLocker locker2(&m_stateChangeLock);
3032 
3033  LOG(VB_CHANNEL, LOG_INFO, LOC +
3034  QString("SetChannel(%1) -- begin").arg(name));
3035 
3036  // Detect tuning request type if needed
3037  if (requestType & kFlagDetect)
3038  {
3040  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3041  }
3042 
3043  // Clear the RingBuffer reset flag, in case we wait for a reset below
3044  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3045 
3046  // Clear out any EITScan channel change requests
3047  auto it = m_tuningRequests.begin();
3048  while (it != m_tuningRequests.end())
3049  {
3050  if ((*it).m_flags & kFlagEITScan)
3051  it = m_tuningRequests.erase(it);
3052  else
3053  ++it;
3054  }
3055 
3056  // Actually add the tuning request to the queue, and
3057  // then wait for it to start tuning
3058  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3060 
3061  // If we are using a recorder, wait for a RingBuffer reset
3062  if (requestType & kFlagRec)
3063  {
3064  while (!HasFlags(kFlagRingBufferReady))
3066  }
3067  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3068 }
3069 
3077 bool TVRec::QueueEITChannelChange(const QString &name)
3078 {
3079  LOG(VB_CHANNEL, LOG_INFO, LOC +
3080  QString("QueueEITChannelChange(%1) -- begin").arg(name));
3081 
3082  bool ok = false;
3083  if (m_setChannelLock.tryLock())
3084  {
3085  if (m_stateChangeLock.tryLock())
3086  {
3087  if (m_tuningRequests.empty())
3088  {
3090  ok = true;
3091  }
3092  m_stateChangeLock.unlock();
3093  }
3094  m_setChannelLock.unlock();
3095  }
3096 
3097  LOG(VB_CHANNEL, LOG_INFO, LOC +
3098  QString("QueueEITChannelChange(%1) -- end --> %2").arg(name).arg(ok));
3099 
3100  return ok;
3101 }
3102 
3104  QString &title, QString &subtitle,
3105  QString &desc, QString &category,
3106  QString &starttime, QString &endtime,
3107  QString &callsign, QString &iconpath,
3108  QString &channum, uint &sourceChanid,
3109  QString &seriesid, QString &programid)
3110 {
3111  QString compare = "<=";
3112  QString sortorder = "desc";
3113  uint chanid = 0;
3114 
3115  if (sourceChanid)
3116  {
3117  chanid = sourceChanid;
3118 
3119  if (BROWSE_UP == direction)
3120  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3121  else if (BROWSE_DOWN == direction)
3122  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3123  else if (BROWSE_FAVORITE == direction)
3124  {
3125  chanid = m_channel->GetNextChannel(
3126  chanid, CHANNEL_DIRECTION_FAVORITE);
3127  }
3128  else if (BROWSE_LEFT == direction)
3129  {
3130  compare = "<";
3131  }
3132  else if (BROWSE_RIGHT == direction)
3133  {
3134  compare = ">";
3135  sortorder = "asc";
3136  }
3137  }
3138 
3139  if (!chanid)
3140  {
3141  if (BROWSE_SAME == direction)
3142  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3143  else if (BROWSE_UP == direction)
3144  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3145  else if (BROWSE_DOWN == direction)
3146  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3147  else if (BROWSE_FAVORITE == direction)
3148  {
3149  chanid = m_channel->GetNextChannel(channum,
3151  }
3152  else if (BROWSE_LEFT == direction)
3153  {
3154  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3155  compare = "<";
3156  }
3157  else if (BROWSE_RIGHT == direction)
3158  {
3159  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3160  compare = ">";
3161  sortorder = "asc";
3162  }
3163  }
3164 
3165  QString querystr = QString(
3166  "SELECT title, subtitle, description, category, "
3167  " starttime, endtime, callsign, icon, "
3168  " channum, seriesid, programid "
3169  "FROM program, channel "
3170  "WHERE program.chanid = channel.chanid AND "
3171  " channel.chanid = :CHANID AND "
3172  " starttime %1 :STARTTIME "
3173  "ORDER BY starttime %2 "
3174  "LIMIT 1").arg(compare, sortorder);
3175 
3176  MSqlQuery query(MSqlQuery::InitCon());
3177  query.prepare(querystr);
3178  query.bindValue(":CHANID", chanid);
3179  query.bindValue(":STARTTIME", starttime);
3180 
3181  // Clear everything now in case either query fails.
3182  title = subtitle = desc = category = "";
3183  starttime = endtime = callsign = iconpath = "";
3184  channum = seriesid = programid = "";
3185  sourceChanid = 0;
3186 
3187  // Try to get the program info
3188  if (!query.exec() && !query.isActive())
3189  {
3190  MythDB::DBError("GetNextProgram -- get program info", query);
3191  }
3192  else if (query.next())
3193  {
3194  title = query.value(0).toString();
3195  subtitle = query.value(1).toString();
3196  desc = query.value(2).toString();
3197  category = query.value(3).toString();
3198  starttime = query.value(4).toString();
3199  endtime = query.value(5).toString();
3200  callsign = query.value(6).toString();
3201  iconpath = query.value(7).toString();
3202  channum = query.value(8).toString();
3203  seriesid = query.value(9).toString();
3204  programid = query.value(10).toString();
3205  sourceChanid = chanid;
3206  return;
3207  }
3208 
3209  // Couldn't get program info, so get the channel info instead
3210  query.prepare(
3211  "SELECT channum, callsign, icon "
3212  "FROM channel "
3213  "WHERE chanid = :CHANID");
3214  query.bindValue(":CHANID", chanid);
3215 
3216  if (!query.exec() || !query.isActive())
3217  {
3218  MythDB::DBError("GetNextProgram -- get channel info", query);
3219  }
3220  else if (query.next())
3221  {
3222  sourceChanid = chanid;
3223  channum = query.value(0).toString();
3224  callsign = query.value(1).toString();
3225  iconpath = query.value(2).toString();
3226  }
3227 }
3228 
3229 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3230  QString &callsign, QString &channum,
3231  QString &channame, QString &xmltvid) const
3232 {
3233  callsign.clear();
3234  channum.clear();
3235  channame.clear();
3236  xmltvid.clear();
3237 
3238  if ((!chanid || !sourceid) && !m_channel)
3239  return false;
3240 
3241  if (!chanid)
3242  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3243 
3244  if (!sourceid)
3245  sourceid = m_channel->GetSourceID();
3246 
3247  MSqlQuery query(MSqlQuery::InitCon());
3248  query.prepare(
3249  "SELECT callsign, channum, name, xmltvid "
3250  "FROM channel "
3251  "WHERE chanid = :CHANID");
3252  query.bindValue(":CHANID", chanid);
3253  if (!query.exec() || !query.isActive())
3254  {
3255  MythDB::DBError("GetChannelInfo", query);
3256  return false;
3257  }
3258 
3259  if (!query.next())
3260  return false;
3261 
3262  callsign = query.value(0).toString();
3263  channum = query.value(1).toString();
3264  channame = query.value(2).toString();
3265  xmltvid = query.value(3).toString();
3266 
3267  return true;
3268 }
3269 
3270 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3271  const QString& oldchannum,
3272  const QString& callsign, const QString& channum,
3273  const QString& channame, const QString& xmltvid)
3274 {
3275  if (!chanid || !sourceid || channum.isEmpty())
3276  return false;
3277 
3278  MSqlQuery query(MSqlQuery::InitCon());
3279  query.prepare(
3280  "UPDATE channel "
3281  "SET callsign = :CALLSIGN, "
3282  " channum = :CHANNUM, "
3283  " name = :CHANNAME, "
3284  " xmltvid = :XMLTVID "
3285  "WHERE chanid = :CHANID AND "
3286  " sourceid = :SOURCEID");
3287  query.bindValue(":CALLSIGN", callsign);
3288  query.bindValue(":CHANNUM", channum);
3289  query.bindValue(":CHANNAME", channame);
3290  query.bindValue(":XMLTVID", xmltvid);
3291  query.bindValue(":CHANID", chanid);
3292  query.bindValue(":SOURCEID", sourceid);
3293 
3294  if (!query.exec())
3295  {
3296  MythDB::DBError("SetChannelInfo", query);
3297  return false;
3298  }
3299 
3300  if (m_channel)
3301  m_channel->Renumber(sourceid, oldchannum, channum);
3302 
3303  return true;
3304 }
3305 
3310 {
3311  QMutexLocker lock(&m_stateChangeLock);
3312 
3313  MythMediaBuffer *oldbuffer = m_buffer;
3314  m_buffer = Buffer;
3315 
3316  if (oldbuffer && (oldbuffer != Buffer))
3317  {
3319  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3320  delete oldbuffer;
3321  }
3322 
3323  m_switchingBuffer = false;
3324 }
3325 
3327 {
3328  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3329 
3330  if (pginfo)
3331  {
3332  if (m_curRecording)
3333  {
3336  delete m_curRecording;
3337  }
3339  m_curRecording = new RecordingInfo(*pginfo);
3342  }
3343 
3345 }
3346 
3348  QString &input) const
3349 {
3350  QString channum;
3351 
3352  if (request.m_program)
3353  {
3354  request.m_program->QueryTuningInfo(channum, input);
3355  return channum;
3356  }
3357 
3358  channum = request.m_channel;
3359  input = request.m_input;
3360 
3361  // If this is Live TV startup, we need a channel...
3362  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3363  {
3364  if (!m_liveTVStartChannel.isEmpty())
3365  channum = m_liveTVStartChannel;
3366  else
3367  {
3370  }
3371  }
3372  if (request.m_flags & kFlagLiveTV)
3373  m_channel->Init(channum, false);
3374 
3375  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3376  {
3377  // FIXME This is just horrible
3378  int dir = channum.right(channum.length() - 12).toInt();
3379  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3380  channum = ChannelUtil::GetChanNum(chanid);
3381  }
3382 
3383  return channum;
3384 }
3385 
3387 {
3388  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3390  {
3391  return false;
3392  }
3393 
3394  uint sourceid = m_channel->GetSourceID();
3395  QString oldchannum = m_channel->GetChannelName();
3396  QString newchannum = request.m_channel;
3397 
3398  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3399  {
3401  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3402 
3403  if (atsc)
3404  {
3405  uint major = 0;
3406  uint minor = 0;
3407  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3408 
3409  if (minor && atsc->HasChannel(major, minor))
3410  {
3411  request.m_majorChan = major;
3412  request.m_minorChan = minor;
3413  return true;
3414  }
3415  }
3416 
3417  if (mpeg)
3418  {
3419  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3420  if (mpeg->HasProgram(progNum))
3421  {
3422  request.m_progNum = progNum;
3423  return true;
3424  }
3425  }
3426  }
3427 
3428  return false;
3429 }
3430 
3439 {
3440  if (!m_tuningRequests.empty())
3441  {
3442  TuningRequest request = m_tuningRequests.front();
3443  LOG(VB_RECORD, LOG_INFO, LOC +
3444  "HandleTuning Request: " + request.toString());
3445 
3446  QString input;
3447  request.m_channel = TuningGetChanNum(request, input);
3448  request.m_input = input;
3449 
3450  if (TuningOnSameMultiplex(request))
3451  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3452 
3453  TuningShutdowns(request);
3454 
3455  // The dequeue isn't safe to do until now because we
3456  // release the stateChangeLock to teardown a recorder
3458 
3459  // Now we start new stuff
3460  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3462  {
3463  if (!m_recorder)
3464  {
3465  LOG(VB_RECORD, LOG_INFO, LOC +
3466  "No recorder yet, calling TuningFrequency");
3467  TuningFrequency(request);
3468  }
3469  else
3470  {
3471  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3472  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3473  }
3474  }
3475  m_lastTuningRequest = request;
3476  }
3477 
3479  {
3480  if (!m_recorder || !m_recorder->IsPaused())
3481  return;
3482 
3483  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3484  LOG(VB_RECORD, LOG_INFO, LOC +
3485  "Recorder paused, calling TuningFrequency");
3487  }
3488 
3489  MPEGStreamData *streamData = nullptr;
3490  if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3491  return;
3492 
3494  {
3495  if (m_recorder)
3497  else
3498  TuningNewRecorder(streamData);
3499 
3500  // If we got this far it is safe to set a new starting channel...
3501  if (m_channel)
3503  }
3504 }
3505 
3511 {
3512  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3513  .arg(request.toString()));
3514 
3515  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3517  {
3519  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3521  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3522  }
3523 
3524  if (m_scanner && !request.IsOnSameMultiplex())
3526 
3528  {
3529  MPEGStreamData *sd = nullptr;
3530  if (GetDTVSignalMonitor())
3533  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3534 
3535  // Delete StreamData if it is not in use by the recorder.
3536  MPEGStreamData *rec_sd = nullptr;
3537  if (GetDTVRecorder())
3538  rec_sd = GetDTVRecorder()->GetStreamData();
3539  if (sd && (sd != rec_sd))
3540  delete sd;
3541  }
3543  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3544 
3545  // At this point any waits are canceled.
3546 
3547  if (request.m_flags & kFlagNoRec)
3548  {
3550  {
3552  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3554  }
3555 
3557  (m_curRecording &&
3560  {
3561  m_stateChangeLock.unlock();
3562  TeardownRecorder(request.m_flags);
3563  m_stateChangeLock.lock();
3564  }
3565  // At this point the recorders are shut down
3566 
3567  CloseChannel();
3568  // At this point the channel is shut down
3569  }
3570 
3571  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3572  {
3573  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3574  SetRingBuffer(nullptr);
3575  // At this point the ringbuffer is shut down
3576  }
3577 
3578  // Clear pending actions from last request
3579  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3580 }
3581 
3600 {
3601  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningFrequency");
3602 
3603  DTVChannel *dtvchan = GetDTVChannel();
3604  if (dtvchan)
3605  {
3606  MPEGStreamData *mpeg = nullptr;
3607 
3608  if (GetDTVRecorder())
3610 
3611  // Tune with SI table standard (dvb, atsc, mpeg) from database, see issue #452
3613 
3614  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3615  dtvchan->GetSIStandard() :
3616  dtvchan->GetSuggestedTuningMode(
3618 
3619  dtvchan->SetTuningMode(tuningmode);
3620 
3621  if (request.m_minorChan && (tuningmode == "atsc"))
3622  {
3623  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3624  if (atsc)
3625  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3626  }
3627  else if (request.m_progNum >= 0)
3628  {
3629  if (mpeg)
3630  mpeg->SetDesiredProgram(request.m_progNum);
3631  }
3632  }
3633 
3634  if (request.IsOnSameMultiplex())
3635  {
3636  // Update the channel number for SwitchLiveTVRingBuffer (called from
3637  // TuningRestartRecorder). This ensures that the livetvchain will be
3638  // updated with the new channel number
3639  if (m_channel)
3640  {
3642  m_channel->GetChannelName(), request.m_channel );
3643  }
3644 
3645  QStringList slist;
3646  slist<<"message"<<QObject::tr("On known multiplex...");
3647  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3648  gCoreContext->dispatch(me);
3649 
3650  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3651  return;
3652  }
3653 
3654  QString channum = request.m_channel;
3655 
3656  bool ok1 = true;
3657  if (m_channel)
3658  {
3659  m_channel->Open();
3660  if (!channum.isEmpty())
3661  ok1 = m_channel->SetChannelByString(channum);
3662  else
3663  ok1 = false;
3664  }
3665 
3666  if (!ok1)
3667  {
3668  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3669  {
3670  if (m_curRecording)
3672 
3673  LOG(VB_GENERAL, LOG_ERR, LOC +
3674  QString("Failed to set channel to %1. Reverting to kState_None")
3675  .arg(channum));
3678  else
3680  return;
3681  }
3682 
3683  LOG(VB_GENERAL, LOG_ERR, LOC +
3684  QString("Failed to set channel to %1.").arg(channum));
3685  }
3686 
3687 
3688  bool mpts_only = GetDTVChannel() &&
3689  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3690  if (mpts_only)
3691  {
3692  // Not using a signal monitor, so just set the status to recording
3694  if (m_curRecording)
3695  {
3697  }
3698  }
3699 
3700 
3701  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3702  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3703  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3704  bool use_dr = use_sm && (livetv || antadj);
3705  bool has_dummy = false;
3706 
3707  if (use_dr)
3708  {
3709  // We need there to be a ringbuffer for these modes
3710  bool ok2 = false;
3712  m_pseudoLiveTVRecording = nullptr;
3713 
3714  m_tvChain->SetInputType("DUMMY");
3715 
3716  if (!m_buffer)
3717  ok2 = CreateLiveTVRingBuffer(channum);
3718  else
3719  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3721 
3723 
3724  if (!ok2)
3725  {
3726  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3727  return;
3728  }
3729 
3730  has_dummy = true;
3731  }
3732 
3733  // Start signal monitoring for devices capable of monitoring
3734  if (use_sm)
3735  {
3736  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3737  bool error = false;
3738  if (!SetupSignalMonitor(
3739  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3740  {
3741  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3742  if (m_signalMonitor)
3743  {
3744  delete m_signalMonitor;
3745  m_signalMonitor = nullptr;
3746  }
3747 
3748  // pretend the signal monitor is running to prevent segfault
3749  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3750  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3751  error = true;
3752  }
3753 
3754  if (m_signalMonitor)
3755  {
3756  if (request.m_flags & kFlagEITScan)
3757  {
3759  SetVideoStreamsRequired(0);
3761  }
3762 
3763  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3764  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3765  if (!antadj)
3766  {
3767  QDateTime expire = MythDate::current();
3768 
3769  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3770  if (m_curRecording)
3771  {
3773  // If startRecordingDeadline is passed, this
3774  // recording is marked as failed, so the scheduler
3775  // can try another showing.
3777  expire.addMSecs(m_genOpt.m_channelTimeout);
3779  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3780  // Keep trying to record this showing (even if it
3781  // has been marked as failed) until the scheduled
3782  // end time.
3784  m_curRecording->GetRecordingEndTime().addSecs(-10);
3785 
3786  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3787  QString("Pre-fail start deadline: %1 "
3788  "Start recording deadline: %2 "
3789  "Good signal deadline: %3")
3790  .arg(m_preFailDeadline.toLocalTime()
3791  .toString("hh:mm:ss.zzz"),
3792  m_startRecordingDeadline.toLocalTime()
3793  .toString("hh:mm:ss.zzz"),
3794  m_signalMonitorDeadline.toLocalTime()
3795  .toString("hh:mm:ss.zzz")));
3796  }
3797  else
3798  {
3800  expire.addMSecs(m_genOpt.m_channelTimeout);
3801  }
3803 
3804  //System Event TUNING_TIMEOUT deadline
3806  m_signalEventCmdSent = false;
3807  }
3808  }
3809 
3810  if (has_dummy && m_buffer)
3811  {
3812  // Make sure recorder doesn't point to bogus ringbuffer before
3813  // it is potentially restarted without a new ringbuffer, if
3814  // the next channel won't tune and the user exits LiveTV.
3815  if (m_recorder)
3816  m_recorder->SetRingBuffer(nullptr);
3817 
3818  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3819  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3820  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3821  }
3822 
3823  // if we had problems starting the signal monitor,
3824  // we don't want to start the recorder...
3825  if (error)
3826  return;
3827  }
3828 
3829  // Request a recorder, if the command is a recording command
3830  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3831  if (request.m_flags & kFlagRec && !antadj)
3832  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3833 }
3834 
3843 {
3844  RecStatus::Type newRecStatus = RecStatus::Unknown;
3845  bool keep_trying = false;
3846  QDateTime current_time = MythDate::current();
3847 
3848  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3850  {
3851  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3852  .arg(m_inputId));
3853  m_signalEventCmdSent = true;
3854  }
3855 
3856  if (m_signalMonitor->IsAllGood())
3857  {
3858  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3859  if (m_curRecording && (current_time > m_startRecordingDeadline))
3860  {
3861  newRecStatus = RecStatus::Failing;
3862  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3863 
3864  QString desc = tr("Good signal seen after %1 ms")
3865  .arg(m_genOpt.m_channelTimeout +
3866  m_startRecordingDeadline.msecsTo(current_time));
3867  QString title = m_curRecording->GetTitle();
3868  if (!m_curRecording->GetSubtitle().isEmpty())
3869  title += " - " + m_curRecording->GetSubtitle();
3870 
3872  "Recording", title,
3873  tr("See 'Tuning timeout' in mythtv-setup "
3874  "for this input."));
3875  gCoreContext->SendEvent(mn);
3876 
3877  LOG(VB_GENERAL, LOG_WARNING, LOC +
3878  QString("It took longer than %1 ms to get a signal lock. "
3879  "Keeping status of '%2'")
3881  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3882  LOG(VB_GENERAL, LOG_WARNING, LOC +
3883  "See 'Tuning timeout' in mythtv-setup for this input");
3884  }
3885  else
3886  {
3887  newRecStatus = RecStatus::Recording;
3888  }
3889  }
3890  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
3891  {
3892  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
3893  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
3894 
3895  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3896  newRecStatus = RecStatus::Failed;
3897 
3899  {
3901  }
3902  }
3903  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
3904  {
3905  LOG(VB_GENERAL, LOG_ERR, LOC +
3906  "TuningSignalCheck: Hit pre-fail timeout");
3907  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
3908  m_reachedPreFail = true;
3909  return nullptr;
3910  }
3912  current_time > m_startRecordingDeadline)
3913  {
3914  newRecStatus = RecStatus::Failing;
3916  keep_trying = true;
3917 
3918  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
3919 
3920  QString desc = tr("Taking more than %1 ms to get a lock.")
3921  .arg(m_genOpt.m_channelTimeout);
3922  QString title = m_curRecording->GetTitle();
3923  if (!m_curRecording->GetSubtitle().isEmpty())
3924  title += " - " + m_curRecording->GetSubtitle();
3925 
3927  "Recording", title,
3928  tr("See 'Tuning timeout' in mythtv-setup "
3929  "for this input."));
3930  mn.SetDuration(30s);
3931  gCoreContext->SendEvent(mn);
3932 
3933  LOG(VB_GENERAL, LOG_WARNING, LOC +
3934  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
3935  "marking this recording as '%2'.")
3937  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3938  LOG(VB_GENERAL, LOG_WARNING, LOC +
3939  "See 'Tuning timeout' in mythtv-setup for this input");
3940  }
3941  else
3942  {
3943  if (m_signalMonitorCheckCnt) // Don't flood log file
3945  else
3946  {
3947  LOG(VB_RECORD, LOG_INFO, LOC +
3948  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
3949  .arg(m_signalMonitorDeadline.toLocalTime()
3950  .toString("hh:mm:ss.zzz")));
3952  }
3953  return nullptr;
3954  }
3955 
3956  SetRecordingStatus(newRecStatus, __LINE__);
3957 
3958  if (m_curRecording)
3959  {
3960  m_curRecording->SetRecordingStatus(newRecStatus);
3961  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
3962  .arg(m_curRecording->GetInputID())
3963  .arg(m_curRecording->GetChanID())
3965  .arg(newRecStatus)
3967  gCoreContext->dispatch(me);
3968  }
3969 
3970  if (keep_trying)
3971  return nullptr;
3972 
3973  // grab useful data from DTV signal monitor before we kill it...
3974  MPEGStreamData *streamData = nullptr;
3975  if (GetDTVSignalMonitor())
3976  streamData = GetDTVSignalMonitor()->GetStreamData();
3977 
3979  {
3980  // shut down signal monitoring
3982  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3983  }
3984  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3985 
3986  if (streamData)
3987  {
3988  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
3989  if (dsd)
3991  if (!get_use_eit(GetInputId()))
3992  {
3993  LOG(VB_EIT, LOG_INFO, LOC +
3994  "EIT scanning disabled for all sources on this input.");
3995  }
3996  else if (m_scanner)
3998  }
3999 
4000  return streamData;
4001 }
4002 
4004  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
4005 {
4006  if (!rec)
4007  return 0; // no jobs for Live TV recordings..
4008 
4009  int jobs = 0; // start with no jobs
4010 
4011  // grab standard jobs flags from program info
4013 
4014  // disable commercial flagging on PBS, BBC, etc.
4015  if (rec->IsCommercialFree())
4017 
4018  // disable transcoding if the profile does not allow auto transcoding
4019  const StandardSetting *autoTrans = profile.byName("autotranscode");
4020  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4022 
4023  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4024  if (ml)
4025  {
4026  // When allowed, metadata lookup should occur at the
4027  // start of a recording to make the additional info
4028  // available immediately (and for use in future jobs).
4029  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4031  rec->GetChanID(),
4032  rec->GetRecordingStartTime(), "", "",
4033  host, JOB_LIVE_REC);
4034 
4035  // don't do regular metadata lookup, we won't need it.
4037  }
4038 
4039  // is commercial flagging enabled, and is on-line comm flagging enabled?
4040  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4041  // also, we either need transcoding to be disabled or
4042  // we need to be allowed to commercial flag before transcoding?
4043  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4044  !transcode_bfr_comm;
4045  if (rt)
4046  {
4047  // queue up real-time (i.e. on-line) commercial flagging.
4048  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4050  rec->GetChanID(),
4051  rec->GetRecordingStartTime(), "", "",
4052  host, JOB_LIVE_REC);
4053 
4054  // don't do regular comm flagging, we won't need it.
4056  }
4057 
4058  return jobs;
4059 }
4060 
4061 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4062  RecordingProfile &profile) const
4063 {
4064  // Determine the correct recording profile.
4065  // In LiveTV mode use "Live TV" profile, otherwise use the
4066  // recording's specified profile. If the desired profile can't
4067  // be found, fall back to the "Default" profile for input type.
4068  QString profileName = "Live TV";
4069  if (!tvchain && rec)
4070  profileName = rec->GetRecordingRule()->m_recProfile;
4071 
4072  QString profileRequested = profileName;
4073 
4074  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4076  {
4077  LOG(VB_RECORD, LOG_INFO, LOC +
4078  QString("Using profile '%1' to record")
4079  .arg(profileName));
4080  }
4081  else
4082  {
4083  profileName = "Default";
4084  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4085  {
4086  LOG(VB_RECORD, LOG_INFO, LOC +
4087  QString("Profile '%1' not found, using "
4088  "fallback profile '%2' to record")
4089  .arg(profileRequested, profileName));
4090  }
4091  else
4092  {
4093  LOG(VB_RECORD, LOG_ERR, LOC +
4094  QString("Profile '%1' not found, and unable "
4095  "to load fallback profile '%2'. Results "
4096  "may be unpredicable")
4097  .arg(profileRequested, profileName));
4098  }
4099  }
4100 
4101  return profileName;
4102 }
4103 
4108 {
4109  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4110 
4111  bool had_dummyrec = false;
4113  {
4115  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4117  had_dummyrec = true;
4118  }
4119 
4121 
4124 
4125  if (m_tvChain)
4126  {
4127  bool ok = false;
4128  if (!m_buffer)
4129  {
4131  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4132  }
4133  else
4135  true, !had_dummyrec && m_recorder);
4136  if (!ok)
4137  {
4138  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4139  goto err_ret;
4140  }
4141  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4142  }
4143 
4145  {
4146  bool write = m_genOpt.m_inputType != "IMPORT";
4147  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4148  .arg(rec->GetPathname()));
4150  if (!m_buffer->IsOpen() && write)
4151  {
4152  LOG(VB_GENERAL, LOG_ERR, LOC +
4153  QString("RingBuffer '%1' not open...")
4154  .arg(rec->GetPathname()));
4155  SetRingBuffer(nullptr);
4156  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4157  goto err_ret;
4158  }
4159  }
4160 
4161  if (!m_buffer)
4162  {
4163  LOG(VB_GENERAL, LOG_ERR, LOC +
4164  QString("Failed to start recorder! ringBuffer is NULL\n"
4165  "\t\t\t\t Tuning request was %1\n")
4166  .arg(m_lastTuningRequest.toString()));
4167 
4168  if (HasFlags(kFlagLiveTV))
4169  {
4170  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4171  MythEvent me(message);
4172  gCoreContext->dispatch(me);
4173  }
4174  goto err_ret;
4175  }
4176 
4177  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4178  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4179 
4180  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4182 
4183  if (m_recorder)
4184  {
4187  if (m_recorder->IsErrored())
4188  {
4189  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4190  delete m_recorder;
4191  m_recorder = nullptr;
4192  }
4193  }
4194 
4195  if (!m_recorder)
4196  {
4197  LOG(VB_GENERAL, LOG_ERR, LOC +
4198  QString("Failed to start recorder!\n"
4199  "\t\t\t\t Tuning request was %1\n")
4200  .arg(m_lastTuningRequest.toString()));
4201 
4202  if (HasFlags(kFlagLiveTV))
4203  {
4204  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4205  MythEvent me(message);
4206  gCoreContext->dispatch(me);
4207  }
4209  goto err_ret;
4210  }
4211 
4212  if (rec)
4213  m_recorder->SetRecording(rec);
4214 
4215  if (GetDTVRecorder() && streamData)
4216  {
4217  const StandardSetting *setting = profile.byName("recordingtype");
4218  if (setting)
4219  streamData->SetRecordingType(setting->getValue());
4220  GetDTVRecorder()->SetStreamData(streamData);
4221  }
4222 
4223  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4224  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4225 
4226  // Setup for framebuffer capture devices..
4227  if (m_channel)
4228  {
4231  }
4232 
4233  if (GetV4LChannel())
4234  {
4236  CloseChannel();
4237  }
4238 
4239  m_recorderThread = new MThread("RecThread", m_recorder);
4241 
4242  // Wait for recorder to start.
4243  m_stateChangeLock.unlock();
4244  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4245  std::this_thread::sleep_for(5us);
4246  m_stateChangeLock.lock();
4247 
4248  if (GetV4LChannel())
4250 
4251  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4252 
4253  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4254 
4255  //workaround for failed import recordings, no signal monitor means we never
4256  //go to recording state and the status here seems to override the status
4257  //set in the importrecorder and backend via setrecordingstatus
4258  if (m_genOpt.m_inputType == "IMPORT")
4259  {
4261  if (m_curRecording)
4263  }
4264  return;
4265 
4266  err_ret:
4267  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4269 
4270  if (rec)
4271  {
4272  // Make sure the scheduler knows...
4274  LOG(VB_RECORD, LOG_INFO, LOC +
4275  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4277  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4278  .arg(rec->GetInputID())
4279  .arg(rec->GetChanID())
4281  .arg(RecStatus::Failed)
4283  gCoreContext->dispatch(me);
4284  }
4285 
4286  if (m_tvChain)
4287  delete rec;
4288 }
4289 
4294 {
4295  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4296 
4297  bool had_dummyrec = false;
4298 
4299  if (m_curRecording)
4300  {
4303  }
4304 
4306  {
4307  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4308  had_dummyrec = true;
4309  }
4310 
4311  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4312 
4313  if (had_dummyrec)
4314  {
4316  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4317  RecordingInfo recinfo(*progInfo);
4318  delete progInfo;
4319  recinfo.SetInputID(m_inputId);
4320  m_recorder->SetRecording(&recinfo);
4321  }
4322  m_recorder->Reset();
4323 
4324  // Set file descriptor of channel from recorder for V4L
4325  if (GetV4LChannel())
4327 
4328  // Some recorders unpause on Reset, others do not...
4329  m_recorder->Unpause();
4330 
4332  {
4334  QString msg1 = QString("Recording: %1 %2 %3 %4")
4335  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4338  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4339  QString msg2 = QString("Recording: %1 %2 %3 %4")
4340  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4343  delete rcinfo2;
4344  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4345  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4346 
4349 
4351 
4352  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4353  }
4354 
4355  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4356 }
4357 
4358 void TVRec::SetFlags(uint f, const QString & file, int line)
4359 {
4360  QMutexLocker lock(&m_stateChangeLock);
4361  m_stateFlags |= f;
4362  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4363  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4364  WakeEventLoop();
4365 }
4366 
4367 void TVRec::ClearFlags(uint f, const QString & file, int line)
4368 {
4369  QMutexLocker lock(&m_stateChangeLock);
4370  m_stateFlags &= ~f;
4371  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4372  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4373  WakeEventLoop();
4374 }
4375 
4377 {
4378  QString msg("");
4379 
4380  // General flags
4381  if (kFlagFrontendReady & f)
4382  msg += "FrontendReady,";
4383  if (kFlagRunMainLoop & f)
4384  msg += "RunMainLoop,";
4385  if (kFlagExitPlayer & f)
4386  msg += "ExitPlayer,";
4387  if (kFlagFinishRecording & f)
4388  msg += "FinishRecording,";
4389  if (kFlagErrored & f)
4390  msg += "Errored,";
4391  if (kFlagCancelNextRecording & f)
4392  msg += "CancelNextRecording,";
4393 
4394  // Tuning flags
4395  if ((kFlagRec & f) == kFlagRec)
4396  msg += "REC,";
4397  else
4398  {
4399  if (kFlagLiveTV & f)
4400  msg += "LiveTV,";
4401  if (kFlagRecording & f)
4402  msg += "Recording,";
4403  }
4404  if ((kFlagNoRec & f) == kFlagNoRec)
4405  msg += "NOREC,";
4406  else
4407  {
4408  if (kFlagEITScan & f)
4409  msg += "EITScan,";
4410  if (kFlagCloseRec & f)
4411  msg += "CloseRec,";
4412  if (kFlagKillRec & f)
4413  msg += "KillRec,";
4414  if (kFlagAntennaAdjust & f)
4415  msg += "AntennaAdjust,";
4416  }
4418  msg += "PENDINGACTIONS,";
4419  else
4420  {
4421  if (kFlagWaitingForRecPause & f)
4422  msg += "WaitingForRecPause,";
4423  if (kFlagWaitingForSignal & f)
4424  msg += "WaitingForSignal,";
4425  if (kFlagNeedToStartRecorder & f)
4426  msg += "NeedToStartRecorder,";
4427  if (kFlagKillRingBuffer & f)
4428  msg += "KillRingBuffer,";
4429  }
4430  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4431  msg += "ANYRUNNING,";
4432  else
4433  {
4434  if (kFlagSignalMonitorRunning & f)
4435  msg += "SignalMonitorRunning,";
4436  if (kFlagEITScannerRunning & f)
4437  msg += "EITScannerRunning,";
4439  msg += "ANYRECRUNNING,";
4440  else
4441  {
4442  if (kFlagDummyRecorderRunning & f)
4443  msg += "DummyRecorderRunning,";
4444  if (kFlagRecorderRunning & f)
4445  msg += "RecorderRunning,";
4446  }
4447  }
4448  if (kFlagRingBufferReady & f)
4449  msg += "RingBufferReady,";
4450 
4451  if (msg.isEmpty())
4452  msg = QString("0x%1").arg(f,0,16);
4453 
4454  return msg;
4455 }
4456 
4458 {
4459  QMutexLocker lock(&m_nextLiveTVDirLock);
4460 
4461  bool found = !m_nextLiveTVDir.isEmpty();
4462  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4463  {
4464  found = !m_nextLiveTVDir.isEmpty();
4465  }
4466 
4467  return found;
4468 }
4469 
4470 void TVRec::SetNextLiveTVDir(QString dir)
4471 {
4472  QMutexLocker lock(&m_nextLiveTVDirLock);
4473 
4474  m_nextLiveTVDir = std::move(dir);
4475  m_triggerLiveTVDir.wakeAll();
4476 }
4477 
4480  const QString & channum)
4481 {
4482  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4483  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4484  return false;
4485 
4486  m_nextLiveTVDirLock.lock();
4487  m_nextLiveTVDir.clear();
4488  m_nextLiveTVDirLock.unlock();
4489 
4490  // Dispatch this early, the response can take a while.
4491  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4492  gCoreContext->dispatch(me);
4493 
4494  uint sourceid = m_channel->GetSourceID();
4495  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4496 
4497  if (chanid < 0)
4498  {
4499  // Test setups might have zero channels
4500  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4501  chanid = 9999;
4502  else
4503  {
4504  LOG(VB_GENERAL, LOG_ERR, LOC +
4505  QString("Channel: \'%1\' was not found in the database.\n"
4506  "\t\tMost likely, the 'starting channel' for this "
4507  "Input Connection is invalid.\n"
4508  "\t\tCould not start livetv.").arg(channum));
4509  return false;
4510  }
4511  }
4512 
4513  auto hoursMax =
4514  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4515  if (hoursMax <= 0h)
4516  hoursMax = 8h;
4517 
4518  RecordingInfo *prog = nullptr;
4521  else
4522  {
4523  prog = new RecordingInfo(
4524  chanid, MythDate::current(true), true, hoursMax);
4525  }
4526 
4527  prog->SetInputID(m_inputId);
4528 
4529  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4530  {
4531  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4532  "\n\t\t\tProgramInfo is invalid."
4533  "\n" + prog->toString());
4534  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4536 
4537  prog->SetChanID(chanid);
4538  }
4539 
4542 
4543  prog->SetStorageGroup("LiveTV");
4544 
4545  if (WaitForNextLiveTVDir())
4546  {
4547  QMutexLocker lock(&m_nextLiveTVDirLock);
4549  }
4550  else
4551  {
4552  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4553  prog->SetPathname(sgroup.FindNextDirMostFree());
4554  }
4555 
4557  prog->SetRecordingGroup("LiveTV");
4558 
4559  StartedRecording(prog);
4560 
4561  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4562  if (!(*Buffer) || !(*Buffer)->IsOpen())
4563  {
4564  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4565  .arg(prog->GetPathname()));
4566 
4567  delete *Buffer;
4568  delete prog;
4569 
4570  return false;
4571  }
4572 
4573  *pginfo = prog;
4574  return true;
4575 }
4576 
4577 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4578 {
4579  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4580  .arg(channum));
4581 
4582  RecordingInfo *pginfo = nullptr;
4583  MythMediaBuffer *buffer = nullptr;
4584 
4585  if (!m_channel ||
4586  !m_channel->CheckChannel(channum))
4587  {
4589  return false;
4590  }
4591 
4592  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4593  {
4594  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4596  LOG(VB_GENERAL, LOG_ERR, LOC +
4597  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4598  return false;
4599  }
4600 
4601  SetRingBuffer(buffer);
4602 
4606 
4607  bool discont = (m_tvChain->TotalSize() > 0);
4609  m_channel->GetInputName(), discont);
4610 
4611  if (m_curRecording)
4612  {
4614  delete m_curRecording;
4615  }
4616 
4617  m_curRecording = pginfo;
4619 
4620  return true;
4621 }
4622 
4623 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4624  bool discont, bool set_rec)
4625 {
4626  QString msg;
4627  if (m_curRecording)
4628  {
4629  msg = QString(" curRec(%1) curRec.size(%2)")
4630  .arg(m_curRecording->MakeUniqueKey())
4631  .arg(m_curRecording->GetFilesize());
4632  }
4633  LOG(VB_RECORD, LOG_INFO, LOC +
4634  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4635  .arg(discont).arg(set_rec) + msg);
4636 
4637  RecordingInfo *pginfo = nullptr;
4638  MythMediaBuffer *buffer = nullptr;
4639 
4640  if (!m_channel ||
4641  !m_channel->CheckChannel(channum))
4642  {
4644  return false;
4645  }
4646 
4647  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4648  {
4650  return false;
4651  }
4652 
4653  QString oldinputtype = m_tvChain->GetInputType(-1);
4654 
4655  pginfo->MarkAsInUse(true, kRecorderInUseID);
4660  m_channel->GetInputName(), discont);
4661 
4662  if (set_rec && m_recorder)
4663  {
4664  m_recorder->SetNextRecording(pginfo, buffer);
4665  if (discont)
4667  delete pginfo;
4668  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4669  }
4670  else if (!set_rec)
4671  {
4672  // dummy recordings are finished before this
4673  // is called and other recordings must be finished..
4674  if (m_curRecording && oldinputtype != "DUMMY")
4675  {
4678  delete m_curRecording;
4679  }
4680  m_curRecording = pginfo;
4681  SetRingBuffer(buffer);
4682  }
4683  else
4684  {
4685  delete buffer;
4686  }
4687 
4688  return true;
4689 }
4690 
4692 {
4693  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4694 
4695  if (m_switchingBuffer)
4696  {
4697  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4698  "already switching.");
4699  return nullptr;
4700  }
4701 
4702  if (!m_recorder)
4703  {
4704  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4705  "invalid recorder.");
4706  return nullptr;
4707  }
4708 
4709  if (!m_curRecording)
4710  {
4711  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4712  "invalid recording.");
4713  return nullptr;
4714  }
4715 
4716  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4717  {
4718  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4719  "Not the same channel.");
4720  return nullptr;
4721  }
4722 
4723  auto *ri = new RecordingInfo(rcinfo);
4725 
4726  QString pn = LoadProfile(nullptr, ri, profile);
4727 
4728  if (pn != m_recProfileName)
4729  {
4730  LOG(VB_RECORD, LOG_ERR, LOC +
4731  QString("SwitchRecordingRingBuffer() -> "
4732  "cannot switch profile '%1' to '%2'")
4733  .arg(m_recProfileName, pn));
4734  return nullptr;
4735  }
4736 
4738 
4739  ri->MarkAsInUse(true, kRecorderInUseID);
4740  StartedRecording(ri);
4741 
4742  bool write = m_genOpt.m_inputType != "IMPORT";
4743  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4744  if (!buffer || !buffer->IsOpen())
4745  {
4746  delete buffer;
4747  ri->SetRecordingStatus(RecStatus::Failed);
4748  FinishedRecording(ri, nullptr);
4749  ri->MarkAsInUse(false, kRecorderInUseID);
4750  delete ri;
4751  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4752  "Failed to create new RB.");
4753  return nullptr;
4754  }
4755 
4756  m_recorder->SetNextRecording(ri, buffer);
4757  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4759  m_switchingBuffer = true;
4760  ri->SetRecordingStatus(RecStatus::Recording);
4761  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4762  return ri;
4763 }
4764 
4766 {
4767  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4768  if (it == s_inputs.constEnd())
4769  return nullptr;
4770  return *it;
4771 }
4772 
4773 QString TuningRequest::toString(void) const
4774 {
4775  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4776  .arg((m_program == nullptr) ? QString("NULL") : m_program->toString(),
4778 }
4779 
4780 #ifdef USING_DVB
4781 #include "recorders/dvbchannel.h"
4783 {
4784  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4785  // We need to tell the stream data class to not check the CRC on
4786  // these devices. This can cause segfaults.
4787  auto * dvb = dynamic_cast<DVBChannel*>(c);
4788  if (dvb != nullptr)
4789  s->SetIgnoreCRC(dvb->HasCRCBug());
4790 }
4791 #else
4793 #endif // USING_DVB
4794 
4795 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:67
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4577
kLiveTVAutoExpire
@ kLiveTVAutoExpire
Definition: programtypes.h:198
DTVChannel::GetMajorChannel
uint GetMajorChannel(void) const
Returns major channel, 0 if unknown.
Definition: dtvchannel.h:94
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:213
BROWSE_LEFT
@ BROWSE_LEFT
Fetch information on current channel in the past.
Definition: tv.h:43
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
RecStatus::Type
Type
Definition: recStatus.h:16
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
ChannelBase::Close
virtual void Close(void)=0
Closes the channel changing hardware to use.
TVRec::SetFlags
void SetFlags(uint f, const QString &file, int line)
Definition: tv_rec.cpp:4358
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2566
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
DTVSignalMonitor::AddFlags
void AddFlags(uint64_t _flags) override
Definition: dtvsignalmonitor.cpp:140
dtvchannel.h
TVRec::IsReallyRecording
bool IsReallyRecording(void)
Returns true if frontend can consider the recorder started.
Definition: tv_rec.cpp:2413
mpeg
Definition: mythchrono.h:51
ProgramInfo::MakeUniqueKey
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:339
TVRec::m_runJobOnHostOnly
bool m_runJobOnHostOnly
Definition: tv_rec.h:361
PendingInfo::m_possibleConflicts
std::vector< uint > m_possibleConflicts
Definition: tv_rec.h:140
ChannelBase::Init
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:66
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:85
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:212
TVRec::kFlagNoRec
static const uint kFlagNoRec
Definition: tv_rec.h:464
TVRec::RecordPending
void RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:290
TVRec::kFlagErrored
static const uint kFlagErrored
Definition: tv_rec.h:444
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
TVRec::m_startRecordingDeadline
QDateTime m_startRecordingDeadline
Definition: tv_rec.h:345
TVRec::m_channel
ChannelBase * m_channel
Definition: tv_rec.h:338
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
MARK_ASPECT_16_9
@ MARK_ASPECT_16_9
Definition: programtypes.h:68
JobQueue::RemoveJobsFromMask
static void RemoveJobsFromMask(int jobs, int &mask)
Definition: jobqueue.h:200
TVRec::kFlagEITScannerRunning
static const uint kFlagEITScannerRunning
Definition: tv_rec.h:475
RecordingInfo::FinishedRecording
void FinishedRecording(bool allowReRecord)
If not a premature stop, adds program to history of recorded programs.
Definition: recordinginfo.cpp:1222
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
BROWSE_UP
@ BROWSE_UP
Fetch information on previous channel.
Definition: tv.h:41
JobQueue::JobIsInMask
static bool JobIsInMask(int job, int mask)
Definition: jobqueue.h:196
TVRec::SetPseudoLiveTVRecording
void SetPseudoLiveTVRecording(RecordingInfo *pi)
Sets the pseudo LiveTV RecordingInfo.
Definition: tv_rec.cpp:342
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:249
MARK_ASPECT_2_21_1
@ MARK_ASPECT_2_21_1
Definition: programtypes.h:69
DTVSignalMonitor::SetDVBService
void SetDVBService(uint network_id, uint transport_id, int service_id)
Definition: dtvsignalmonitor.cpp:229
TuningRequest
Definition: tv_rec.h:103
EITScanner::StopEITEventProcessing
void StopEITEventProcessing(void)
Stops inserting Event Information Tables into DB.
Definition: eitscanner.cpp:215
TVRec::WaitForEventThreadSleep
bool WaitForEventThreadSleep(bool wake=true, std::chrono::milliseconds time=std::chrono::milliseconds::max())
Definition: tv_rec.cpp:1545
error
static void error(const char *str,...)
Definition: vbi.cpp:35
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ProgramInfo::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type status)
Definition: programinfo.h:582
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:31
dtvrecorder.h
ProgramInfo::QueryMplexID
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
Definition: programinfo.cpp:2654
TVRec::m_recProfileName
QString m_recProfileName
Definition: tv_rec.h:379
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:28
TVRec::m_audioSampleRateDB
int m_audioSampleRateDB
Definition: tv_rec.h:364
mythdb.h
RecorderBase::CreateRecorder
static RecorderBase * CreateRecorder(TVRec *tvrec, ChannelBase *channel, RecordingProfile &profile, const GeneralDBOptions &genOpt)
Definition: recorderbase.cpp:852
TVRec::ShouldSwitchToAnotherInput
bool ShouldSwitchToAnotherInput(const QString &chanid) const
Checks if named channel exists on current tuner, or another tuner.
Definition: tv_rec.cpp:2122
TVRec::kFlagRecording
static const uint kFlagRecording
final result desired is a timed recording
Definition: tv_rec.h:451
mythrandom.h
RecordingRule::Save
bool Save(bool sendSig=true)
Definition: recordingrule.cpp:382
SignalMonitor::IsAllGood
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:86
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:30
JobQueue::QueueJob
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, const QString &args="", const QString &comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
Definition: jobqueue.cpp:522
CardUtil::GetInputName
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1696
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
TVRec::m_triggerEventSleepLock
QMutex m_triggerEventSleepLock
Definition: tv_rec.h:401
ChannelBase::Open
virtual bool Open(void)=0
Opens the channel changing hardware for use.
TVRec::m_tuningRequests
TuningQueue m_tuningRequests
Definition: tv_rec.h:395
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:31
ChannelBase::GetInputName
virtual QString GetInputName(void) const
Definition: channelbase.h:69
kRecorderInUseID
const QString kRecorderInUseID
Definition: programtypes.cpp:20
MythNotification::SetDuration
void SetDuration(std::chrono::seconds Duration)
Contains a duration during which the notification will be displayed for. The duration is informative ...
Definition: mythnotification.cpp:136
RecordingInfo::ApplyRecordRecID
void ApplyRecordRecID(void)
Sets recordid to match RecordingRule recordid.
Definition: recordinginfo.cpp:538
PictureAdjustType
PictureAdjustType
Definition: tv.h:120
MPEGStreamData::SetCaching
void SetCaching(bool cacheTables)
Definition: mpegstreamdata.h:91
ProgramInfo::SetRecordingID
virtual void SetRecordingID(uint _recordedid)
Definition: programinfo.h:580
TVRec::Init
bool Init(void)
Performs instance initialization, returns true on success.
Definition: tv_rec.cpp:155
SignalMonitor::IsSupported
static bool IsSupported(const QString &cardtype)
Definition: signalmonitor.h:324
MythMediaBuffer::StopReads
void StopReads(void)
Definition: mythmediabuffer.cpp:663
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:303
eitscanner.h
RecStatus::Tuning
@ Tuning
Definition: recStatus.h:22
TVRec::IsBusy
bool IsBusy(InputInfo *busy_input=nullptr, std::chrono::seconds time_buffer=5s) const
Returns true if the recorder is busy, or will be within the next time_buffer seconds.
Definition: tv_rec.cpp:2424
pid_cache_item_t
Definition: channelutil.h:24
EITScanner::StartEITEventProcessing
void StartEITEventProcessing(ChannelBase *channel, EITSource *eitSource)
Start inserting Event Information Tables from the multiplex we happen to be tuned to into the databas...
Definition: eitscanner.cpp:183
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
TVRec::ToggleChannelFavorite
void ToggleChannelFavorite(const QString &changroupname)
Toggles whether the current channel should be on our favorites list.
Definition: tv_rec.cpp:2894
GeneralDBOptions::m_signalTimeout
uint m_signalTimeout
Definition: tv_rec.h:78
TVRec::m_eitTransportTimeout
std::chrono::seconds m_eitTransportTimeout
Definition: tv_rec.h:363
RecordingInfo::GetFilesize
uint64_t GetFilesize(void) const override
Definition: recordinginfo.cpp:1708
ChannelBase::IsOpen
virtual bool IsOpen(void) const =0
Reports whether channel is already open.
ProgramInfo::QueryAverageScanProgressive
bool QueryAverageScanProgressive(void) const
If present in recording this loads average video scan type of the main video stream from database's s...
Definition: programinfo.cpp:4530
RecorderBase::Unpause
virtual void Unpause(void)
Unpause tells recorder to unpause.
Definition: recorderbase.cpp:274
TVRec::kFlagRingBufferReady
static const uint kFlagRingBufferReady
Definition: tv_rec.h:483
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:446
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1787
TVRec::m_buffer
MythMediaBuffer * m_buffer
Definition: tv_rec.h:428
RecorderBase::IsErrored
virtual bool IsErrored(void)=0
Tells us whether an unrecoverable error has been encountered.
LiveTVChain::GetID
QString GetID(void) const
Definition: livetvchain.h:56
TVRec::m_triggerLiveTVDir
QWaitCondition m_triggerLiveTVDir
Definition: tv_rec.h:421
RecStatus::Cancelled
@ Cancelled
Definition: recStatus.h:26
TVRec::m_eventThread
MThread * m_eventThread
Event processing thread, runs TVRec::run().
Definition: tv_rec.h:354
TVRec::kFlagRecorderRunning
static const uint kFlagRecorderRunning
Definition: tv_rec.h:478
GeneralDBOptions::m_inputType
QString m_inputType
Definition: tv_rec.h:75
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
TVRec::kFlagRec
static const uint kFlagRec
Definition: tv_rec.h:454
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:77
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:511
TVRec::m_recStatus
RecStatus::Type m_recStatus
Definition: tv_rec.h:405
ChannelUtil::GetATSCChannel
static bool GetATSCChannel(uint sourceid, const QString &channum, uint &major, uint &minor)
Definition: channelutil.cpp:1854
TVRec::SetInput
QString SetInput(QString input)
Changes to the specified input.
Definition: tv_rec.cpp:3002
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
ChannelUtil::GetProgramNumber
static int GetProgramNumber(uint sourceid, const QString &channum)
Definition: channelutil.h:189
SignalMonitor::kDTVSigMon_WaitForMGT
static const uint64_t kDTVSigMon_WaitForMGT
Definition: signalmonitor.h:186
TVRec::GetSourceID
uint GetSourceID(void) const
Returns current source id.
Definition: tv_rec.cpp:2987
JobQueue::QueueRecordingJobs
static bool QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes=JOB_NONE)
Definition: jobqueue.cpp:500
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:202
TVRec::m_overRecordCategory
QString m_overRecordCategory
Definition: tv_rec.h:367
PendingInfo::m_hasLaterShowing
bool m_hasLaterShowing
Definition: tv_rec.h:136
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:369
RecStatus::TunerBusy
@ TunerBusy
Definition: recStatus.h:24
DTVRecorder::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Definition: dtvrecorder.cpp:216
TVRec::GetProgramRingBufferForLiveTV
bool GetProgramRingBufferForLiveTV(RecordingInfo **pginfo, MythMediaBuffer **Buffer, const QString &channum)
Definition: tv_rec.cpp:4478
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:73
PendingInfo::m_info
ProgramInfo * m_info
Definition: tv_rec.h:134
MythNotification
Definition: mythnotification.h:29
DTVChannel::GetMinorChannel
uint GetMinorChannel(void) const
Returns minor channel, 0 if unknown.
Definition: dtvchannel.h:98
RecStatus::Unknown
@ Unknown
Definition: recStatus.h:32
apply_broken_dvb_driver_crc_hack
static void apply_broken_dvb_driver_crc_hack(ChannelBase *, MPEGStreamData *)
Definition: tv_rec.cpp:4782
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4773
RecordingRule::m_endOffset
int m_endOffset
Definition: recordingrule.h:108
ChannelBase::CreateChannel
static ChannelBase * CreateChannel(TVRec *tvrec, const GeneralDBOptions &genOpt, const DVBDBOptions &dvbOpt, const FireWireDBOptions &fwOpt, const QString &startchannel, bool enter_power_save_mode, QString &rbFileExt, bool setchan)
Definition: channelbase.cpp:698
DTVSignalMonitor::GetStreamData
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
Definition: dtvsignalmonitor.h:59
LiveTVChain::TotalSize
int TotalSize(void) const
Definition: livetvchain.cpp:388
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
osd.h
atscstreamdata.h
TVRec::m_curRecording
RecordingInfo * m_curRecording
Definition: tv_rec.h:408
ProgramInfo::SaveCommFlagged
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
Definition: programinfo.cpp:3343
RecStatus::Recorded
@ Recorded
Definition: recStatus.h:29
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:725
RecorderBase::GetKeyframePositions
bool GetKeyframePositions(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:540
MythMediaBuffer
Definition: mythmediabuffer.h:50
DTVChannel::GetFormat
QString GetFormat(void)
Definition: dtvchannel.h:46
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:397
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
FireWireDBOptions::m_speed
int m_speed
Definition: tv_rec.h:98
RecordingInfo::kLiveTVRecGroup
@ kLiveTVRecGroup
Definition: recordinginfo.h:192
TVRec::GetFramesWritten
long long GetFramesWritten(void)
Returns number of frames written to disk by recorder.
Definition: tv_rec.cpp:2507
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1660
channelbase.h
TableID::CVCT
@ CVCT
Definition: mpegtables.h:363
ProgramInfo::UpdateInUseMark
void UpdateInUseMark(bool force=false)
Definition: programinfo.cpp:4884
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:2977
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:460
TVRec::kFlagDummyRecorderRunning
static const uint kFlagDummyRecorderRunning
Definition: tv_rec.h:477
ChannelBase::GetChannelName
virtual QString GetChannelName(void) const
Definition: channelbase.h:64
TVRec::m_setChannelLock
QMutex m_setChannelLock
Definition: tv_rec.h:382
RecordingQuality::IsDamaged
bool IsDamaged(void) const
Definition: recordingquality.cpp:108
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
RecordingInfo::UpdateRecordingEnd
void UpdateRecordingEnd(void)
Update information in the recorded table when the end-time of a recording is changed.
Definition: recordinginfo.cpp:1262
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1202
TVRec::kFlagPendingActions
static const uint kFlagPendingActions
Definition: tv_rec.h:471
TVRec::CheckChannelPrefix
bool CheckChannelPrefix(const QString &prefix, uint &complete_valid_channel_on_rec, bool &is_extra_char_useful, QString &needed_spacer) const
Checks a prefix against the channels in the DB.
Definition: tv_rec.cpp:2258
RecorderBase::Pause
virtual void Pause(bool clear=true)
Pause tells recorder to pause, it should not block.
Definition: recorderbase.cpp:263
MasterGuideTable::TableCount
uint TableCount() const
Definition: atsctables.h:117
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:412
ChannelBase::GetPictureAttribute
virtual int GetPictureAttribute(PictureAttribute) const
Definition: channelbase.h:94
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
TVRec::GetChainID
QString GetChainID(void)
Get the chainid of the livetv instance.
Definition: tv_rec.cpp:2640
remoteutil.h
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
TVRec::m_overRecordSecCat
std::chrono::seconds m_overRecordSecCat
Definition: tv_rec.h:366
RecorderBase::GetKeyframeDurations
bool GetKeyframeDurations(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:562
ProgramInfo::QueryTuningInfo
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
Definition: programinfo.cpp:5268
GetPidsToCache
static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
Definition: tv_rec.cpp:1747
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
TVRec::m_pauseNotify
bool m_pauseNotify
Definition: tv_rec.h:393
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3386
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1128
kState_Error
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:54
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
TVRec::GetFilePosition
long long GetFilePosition(void)
Returns total number of bytes written by RingBuffer.
Definition: tv_rec.cpp:2522
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:343
TVRec::kFlagCancelNextRecording
static const uint kFlagCancelNextRecording
Definition: tv_rec.h:445
RecordingQuality::toStringXML
QString toStringXML(void) const
Definition: recordingquality.cpp:114
ChannelBase::Renumber
virtual void Renumber(uint sourceid, const QString &oldChanNum, const QString &newChanNum)
Changes a channum if we have it cached anywhere.
Definition: channelbase.cpp:629
TVRec::SwitchRecordingRingBuffer
RecordingInfo * SwitchRecordingRingBuffer(const RecordingInfo &rcinfo)
Definition: tv_rec.cpp:4691
tmp
static guint32 * tmp
Definition: goom_core.cpp:32
TVRec::GetRecordEndTime
QDateTime GetRecordEndTime(const ProgramInfo *pi) const
Returns recording end time with proper post-roll.
Definition: tv_rec.cpp:352
TVRec::m_recordEndTime
QDateTime m_recordEndTime
Definition: tv_rec.h:409
DTVChannel::GetTuningMode
QString GetTuningMode(void) const
Returns tuning mode last set by SetTuningMode().
Definition: dtvchannel.cpp:73
kState_ChangingState
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:89
DTVChannel::GetOriginalNetworkID
uint GetOriginalNetworkID(void) const
Returns DVB original_network_id, 0 if unknown.
Definition: dtvchannel.h:102
LiveTVChain::GetProgramAt
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
Definition: livetvchain.cpp:321
kState_None
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:58
EITScanner::StopActiveScan
void StopActiveScan(void)
Definition: eitscanner.cpp:300
SignalMonitor::IsRequired
static bool IsRequired(const QString &cardtype)
Returns true iff the card type supports signal monitoring.
Definition: signalmonitor.h:319
TVRec::TeardownAll
void TeardownAll(void)
Definition: tv_rec.cpp:214
GeneralDBOptions::m_channelTimeout
uint m_channelTimeout
Definition: tv_rec.h:79
MPEGStreamData::SetIgnoreCRC
void SetIgnoreCRC(bool haveCRCbug)
Definition: mpegstreamdata.h:111
TVRec::m_inputId
uint m_inputId
Definition: tv_rec.h:370
GeneralDBOptions::m_vbiDev
QString m_vbiDev
Definition: tv_rec.h:73
TVRec::m_overRecordSecNrml
std::chrono::seconds m_overRecordSecNrml
Definition: tv_rec.h:365
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2885
JOB_LIVE_REC
@ JOB_LIVE_REC
Definition: jobqueue.h:59
MythDate::secsInFuture
std::chrono::seconds secsInFuture(const QDateTime &future)
Definition: mythdate.cpp:209
TVRec::m_pendingRecordings
PendingMap m_pendingRecordings
Definition: tv_rec.h:415
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:1009
TVRec::kFlagAnyRecRunning
static const uint kFlagAnyRecRunning
Definition: tv_rec.h:479
ChannelBase::InitPictureAttributes
virtual bool InitPictureAttributes(void)
Definition: channelbase.h:93
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:236
ProgramInfo::MarkAsInUse
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
Definition: programinfo.cpp:5075
DTVChannel::GetTransportID
uint GetTransportID(void) const
Returns DVB transport_stream_id, 0 if unknown.
Definition: dtvchannel.h:106
MPEGStreamData::ReturnCachedTable
virtual void ReturnCachedTable(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1453
mythdate.h
TVRec::kFlagWaitingForSignal
static const uint kFlagWaitingForSignal
Definition: tv_rec.h:469
TVRec::kFlagDetect
static const uint kFlagDetect
Definition: tv_rec.h:484
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2440
ProgramInfo::SaveVideoProperties
void SaveVideoProperties(uint mask, uint video_property_flags)
Definition: programinfo.cpp:4834
ProgramInfo::SetRecordingEndTime
void SetRecordingEndTime(const QDateTime &dt)
Definition: programinfo.h:528
TVRec::CreateChannel
bool CreateChannel(const QString &startchannel, bool enter_power_save_mode)
Definition: tv_rec.cpp:93
TVRec::m_autoRunJobs
QHash< QString, int > m_autoRunJobs
Definition: tv_rec.h:411
minor
#define minor(X)
Definition: compat.h:76
RecordingInfo::GetRecordingFile
RecordingFile * GetRecordingFile() const
Definition: recordinginfo.h:280
TVRec::PauseRecorder
void PauseRecorder(void)
Tells "recorder" to pause, used for channel and input changes.
Definition: tv_rec.cpp:2866
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2689
ATSCStreamData::SetDesiredChannel
void SetDesiredChannel(int major, int minor)
Definition: atscstreamdata.cpp:57
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1309
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
mythlogging.h
SignalMonitor::kDVBSigMon_WaitForPos
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
Definition: signalmonitor.h:203
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:447
TVRec::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type new_status, int line, bool have_lock=false)
Definition: tv_rec.cpp:695
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4480
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1236
DVBStreamData::SetDishNetEIT
void SetDishNetEIT(bool use_dishnet_eit)
Definition: dvbstreamdata.h:165
LiveTVChain::SetHostPrefix
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:45
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:783
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:98
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
RecorderBase::SetRingBuffer
void SetRingBuffer(MythMediaBuffer *Buffer)
Tells recorder to use an externally created ringbuffer.
Definition: recorderbase.cpp:75
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MasterGuideTable::TablePID
uint TablePID(uint i) const
Definition: atsctables.h:131
CardUtil::IsEncoder
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:130
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:362
TVRec::kFlagKillRec
static const uint kFlagKillRec
close recorder, discard recording
Definition: tv_rec.h:462
ProgramInfo::SetScheduledEndTime
void SetScheduledEndTime(const QDateTime &dt)
Definition: programinfo.h:526
TuningRequest::m_progNum
int m_progNum
Definition: tv_rec.h:124
ProgramInfo::SetInputID
void SetInputID(uint id)
Definition: programinfo.h:542
DTVChannel::SaveCachedPids
void SaveCachedPids(const pid_cache_t &pid_cache) const
Saves MPEG PIDs to cache to database.
Definition: dtvchannel.cpp:107
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1087
TVRec::m_recorder
RecorderBase * m_recorder
Definition: tv_rec.h:337
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1567
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:649
TVRec::GetMaxBitrate
long long GetMaxBitrate(void) const
Returns the maximum bits per second this recorder can produce.
Definition: tv_rec.cpp:2582
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1553
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:441
ProgramInfo::SetRecordingRuleType
void SetRecordingRuleType(RecordingType type)
Definition: programinfo.h:583
TVRec::RemoveRecording
TVState RemoveRecording(TVState state) const
If "state" is kState_RecordingOnly or kState_WatchingLiveTV, returns a kState_None,...
Definition: tv_rec.cpp:772
TVRec::m_pseudoLiveTVRecording
RecordingInfo * m_pseudoLiveTVRecording
Definition: tv_rec.h:418
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:101
hardwareprofile.i18n.t
t
Definition: i18n.py:36
TVRec::FlagToString
static QString FlagToString(uint f)
Definition: tv_rec.cpp:4376
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
compat.h
TVRec::HandleStateChange
void HandleStateChange(void)
Changes the internalState to the desiredNextState if possible.
Definition: tv_rec.cpp:1021
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
TVRec::kAutoRunNone
@ kAutoRunNone
Definition: tv_rec.h:326
LiveTVChain::SetInputType
void SetInputType(const QString &type)
Definition: livetvchain.cpp:50
ATSCStreamData
Encapsulates data about ATSC stream and emits events for most tables.
Definition: atscstreamdata.h:29
v4lchannel.h
TVRec::m_tvChain
LiveTVChain * m_tvChain
Definition: tv_rec.h:425
DVBDBOptions::m_dvbOnDemand
bool m_dvbOnDemand
Definition: tv_rec.h:88
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
TVRec::CheckChannel
bool CheckChannel(const QString &name) const
Checks if named channel exists on current tuner.
Definition: tv_rec.cpp:2212
SignalMonitor::kDTVSigMon_WaitForPMT
static const uint64_t kDTVSigMon_WaitForPMT
Definition: signalmonitor.h:185
RecorderBase::Reset
virtual void Reset(void)=0
Reset the recorder to the startup state.
TVRec::kFlagSignalMonitorRunning
static const uint kFlagSignalMonitorRunning
Definition: tv_rec.h:474
ProgramInfo::SetRecordingGroup
void SetRecordingGroup(const QString &group)
Definition: programinfo.h:529
TVRec::SetupSignalMonitor
bool SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
This creates a SignalMonitor instance and begins signal monitoring.
Definition: tv_rec.cpp:1976
SignalMonitor::kDTVSigMon_WaitForPAT
static const uint64_t kDTVSigMon_WaitForPAT
Definition: signalmonitor.h:184
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:172
TVRec::TuningGetChanNum
QString TuningGetChanNum(const TuningRequest &request, QString &input) const
Definition: tv_rec.cpp:3347
TVRec::kFlagEITScan
static const uint kFlagEITScan
final result desired is an EIT Scan
Definition: tv_rec.h:458
SignalMonitor::kDTVSigMon_WaitForSDT
static const uint64_t kDTVSigMon_WaitForSDT
Definition: signalmonitor.h:189
TVRec::TeardownSignalMonitor
void TeardownSignalMonitor(void)
If a SignalMonitor instance exists, the monitoring thread is stopped and the instance is deleted.
Definition: tv_rec.cpp:2030
RecorderBase::GetRecordingQuality
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Definition: recorderbase.cpp:506
TVRec::WaitForNextLiveTVDir
bool WaitForNextLiveTVDir(void)
Definition: tv_rec.cpp:4457
RecStatus::Failing
@ Failing
Definition: recStatus.h:18
RecordingInfo::SetDesiredStartTime
void SetDesiredStartTime(const QDateTime &dt)
Definition: recordinginfo.h:243
TVRec::kFlagCloseRec
static const uint kFlagCloseRec
close recorder, keep recording
Definition: tv_rec.h:460
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:506
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:462
MPEGStreamData
Encapsulates data about MPEG stream and emits events for each table.
Definition: mpegstreamdata.h:85
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:118
TVRec::m_nextLiveTVDir
QString m_nextLiveTVDir
Definition: tv_rec.h:419
TVRec::m_triggerEventSleepWait
QWaitCondition m_triggerEventSleepWait
Definition: tv_rec.h:402
RecorderBase::GetFrameRate
double GetFrameRate(void) const
Returns the latest frame rate.
Definition: recorderbase.h:234
JobQueue::JobIsNotInMask
static bool JobIsNotInMask(int job, int mask)
Definition: jobqueue.h:197
TVRec::CloseChannel
void CloseChannel(void)
Definition: tv_rec.cpp:1188
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:109
RecStatus::Aborted
@ Aborted
Definition: recStatus.h:28
vboxutils.h
TVRec::kFlagKillRingBuffer
static const uint kFlagKillRingBuffer
Definition: tv_rec.h:465
TVRec::ChangeState
void ChangeState(TVState nextState)
Puts a state change on the nextState queue.
Definition: tv_rec.cpp:1106
DVBStreamData
Definition: dvbstreamdata.h:33
TVRec::m_desiredNextState
TVState m_desiredNextState
Definition: tv_rec.h:391
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1936
TVRec::m_parentId
uint m_parentId
Definition: tv_rec.h:371
TVRec::run
void run(void) override
Event handling method, contains event loop.
Definition: tv_rec.cpp:1292
RecStatus::Failed
@ Failed
Definition: recStatus.h:23
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:400
DTVRecorder::GetStreamData
MPEGStreamData * GetStreamData(void) const
Definition: dtvrecorder.h:57
add_spacer
static QString add_spacer(const QString &channel, const QString &spacer)
Adds the spacer before the last character in chan.
Definition: tv_rec.cpp:2223
RecorderBase::IsRecording
virtual bool IsRecording(void)
Tells whether the StartRecorder() loop is running.
Definition: recorderbase.cpp:243
RecordingRule::GetAutoExpire
AutoExpireType GetAutoExpire(void) const
Definition: recordingrule.h:59
TVRec::TuningShutdowns
void TuningShutdowns(const TuningRequest &request)
This shuts down anything that needs to be shut down before handling the passed in tuning request.
Definition: tv_rec.cpp:3510
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:422
MythNotification::Check
static Type Check
Definition: mythnotification.h:37
storagegroup.h
TVRec::TuningRequest
friend class TuningRequest
Definition: tv_rec.h:148
jobqueue.h
RecorderBase::GetVideoFd
virtual int GetVideoFd(void)=0
Returns file descriptor of recorder device.
TVRec::m_scanner
EITScanner * m_scanner
Definition: tv_rec.h:340
TVRec::m_rbFileExt
QString m_rbFileExt
Definition: tv_rec.h:429
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
LiveTVChain::ReloadAll
void ReloadAll(const QStringList &data=QStringList())
Definition: livetvchain.cpp:210
TVRec::m_eitScanStartTime
QDateTime m_eitScanStartTime
Definition: tv_rec.h:397
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:2943
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4107
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:935
TVRec::GetKeyframePositions
bool GetKeyframePositions(int64_t start, int64_t end, frm_pos_map_t &map) const
Returns byte position in RingBuffer of a keyframes according to recorder.
Definition: tv_rec.cpp:2555
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:432
TVRec::kFlagWaitingForRecPause
static const uint kFlagWaitingForRecPause
Definition: tv_rec.h:468
RecordingQuality
Definition: recordingquality.h:34
DTVRecorder
This is a specialization of RecorderBase used to handle MPEG-2, MPEG-4, MPEG-4 AVC,...
Definition: dtvrecorder.h:25
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:32
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:135
uint
unsigned int uint
Definition: compat.h:79
TVRec::kFlagLiveTV
static const uint kFlagLiveTV
final result desired is LiveTV recording
Definition: tv_rec.h:449
TVRec::SetNextLiveTVDir
void SetNextLiveTVDir(QString dir)
Definition: tv_rec.cpp:4470
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:61
TVRec::GetFramerate
float GetFramerate(void)
Returns recordering frame rate from the recorder.
Definition: tv_rec.cpp:2492
TVRec::m_transcodeFirst
bool m_transcodeFirst
Definition: tv_rec.h:359
TVRec::m_signalEventCmdSent
bool m_signalEventCmdSent
Definition: tv_rec.h:343
TVRec::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: tv_rec.cpp:689
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3077
TVRec::m_eitCrawlIdleStart
std::chrono::seconds m_eitCrawlIdleStart
Definition: tv_rec.h:362
TuningRequest::m_minorChan
uint m_minorChan
Definition: tv_rec.h:123
DTVSignalMonitor::GetATSCStreamData
ATSCStreamData * GetATSCStreamData()
Returns the ATSC stream data if it exists.
Definition: dtvsignalmonitor.cpp:557
TVRec::m_triggerEventLoopWait
QWaitCondition m_triggerEventLoopWait
Definition: tv_rec.h:399
DTVChannel::EnterPowerSavingMode
virtual bool EnterPowerSavingMode(void)
Enters power saving mode if the card supports it.
Definition: dtvchannel.h:65
BROWSE_DOWN
@ BROWSE_DOWN
Fetch information on next channel.
Definition: tv.h:42
InputInfo::Clear
virtual void Clear(void)
Definition: inputinfo.cpp:6
CardUtil::IsV4L
static bool IsV4L(const QString &rawtype)
Definition: cardutil.h:140
TVRec::IsErrored
bool IsErrored(void) const
Returns true is "errored" is true, false otherwise.
Definition: tv_rec.h:240
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:935
RecorderBase::GetFramesWritten
virtual long long GetFramesWritten(void)=0
Returns number of frames written to disk.
ProgramInfo::SaveAutoExpire
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
Definition: programinfo.cpp:3396
ChannelBase::SetFd
virtual void SetFd(int fd)
Sets file descriptor.
Definition: channelbase.h:55
BROWSE_RIGHT
@ BROWSE_RIGHT
Fetch information on current channel in the future.
Definition: tv.h:44
RecordingInfo::LoadRecordingFile
void LoadRecordingFile()
Definition: recordinginfo.cpp:1672
mythmediabuffer.h
TVRec::GetRecording
ProgramInfo * GetRecording(void)
Allocates and returns a ProgramInfo for the current recording.
Definition: tv_rec.cpp:258
TVRec::SpawnLiveTV
void SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
Tells TVRec to spawn a "Live TV" recorder.
Definition: tv_rec.cpp:2610
GeneralDBOptions::m_skipBtAudio
bool m_skipBtAudio
Definition: tv_rec.h:77
TVRec::CancelNextRecording
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the upcoming recording.
Definition: tv_rec.cpp:365
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:46
tvremoteutil.h
SignalMonitor::Init
static SignalMonitor * Init(const QString &cardtype, int db_cardnum, ChannelBase *channel, bool release_stream)
Definition: signalmonitor.cpp:91
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
PictureAttribute
PictureAttribute
Definition: videoouttypes.h:103
RecorderBase::StopRecording
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: recorderbase.cpp:224
TVRec::m_triggerEventSleepSignal
bool m_triggerEventSleepSignal
Definition: tv_rec.h:403
ChannelUtil::GetVideoFilters
static QString GetVideoFilters(uint sourceid, const QString &channum)
Definition: channelutil.h:191
RecorderBase::Initialize
virtual void Initialize(void)=0
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
DTVChannel::GetSIStandard
QString GetSIStandard(void) const
Returns PSIP table standard: MPEG, DVB, ATSC, or OpenCable.
Definition: dtvchannel.cpp:45
RecordingRule::m_recGroupID
uint m_recGroupID
Definition: recordingrule.h:121
SET_NEXT
#define SET_NEXT()
Definition: tv_rec.cpp:1011
TVRec::GetNextProgram
void GetNextProgram(BrowseDirection direction, QString &title, QString &subtitle, QString &desc, QString &category, QString &starttime, QString &endtime, QString &callsign, QString &iconpath, QString &channum, uint &chanid, QString &seriesid, QString &programid)
Definition: tv_rec.cpp:3103
SignalMonitor::HasExtraSlowTuning
virtual bool HasExtraSlowTuning(void) const
Definition: signalmonitor.h:65
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:929
dvbstreamdata.h
DTVSignalMonitor::SetProgramNumber
void SetProgramNumber(int progNum)
Definition: dtvsignalmonitor.cpp:214
MasterGuideTable
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:77
TVRec::m_signalMonitor
SignalMonitor * m_signalMonitor
Definition: tv_rec.h:339
BROWSE_FAVORITE
@ BROWSE_FAVORITE
Fetch information on the next favorite channel.
Definition: tv.h:45
TVRec::GetKeyframePosition
int64_t GetKeyframePosition(uint64_t desired) const
Returns byte position in RingBuffer of a keyframe according to recorder.
Definition: tv_rec.cpp:2538
ChannelGroup::ToggleChannel
static bool ToggleChannel(uint chanid, int changrpid, bool delete_chan)
Definition: channelgroup.cpp:17
TuningRequest::m_majorChan
uint m_majorChan
Definition: tv_rec.h:122
kState_WatchingPreRecorded
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:67
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:463
SignalMonitor::SetUpdateRate
void SetUpdateRate(std::chrono::milliseconds msec)
Sets the number of milliseconds between signal monitoring attempts in the signal monitoring thread.
Definition: signalmonitor.h:114
RecorderBase::SavePositionMap
void SavePositionMap(bool force=false, bool finished=false)
Save the seektable to the DB.
Definition: recorderbase.cpp:592
ProgramInfo::SetChanID
void SetChanID(uint _chanid)
Definition: programinfo.h:524
GeneralDBOptions::m_audioSampleRate
int m_audioSampleRate
Definition: tv_rec.h:76
InputInfo::m_sourceId
uint m_sourceId
associated channel listings source
Definition: inputinfo.h:48
DVBChannel
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:31
LiveTVChain::GetInputType
QString GetInputType(int pos=-1) const
Definition: livetvchain.cpp:696
TuningRequest::m_flags
uint m_flags
Definition: tv_rec.h:118
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
TVRec::m_nextLiveTVDirLock
QMutex m_nextLiveTVDirLock
Definition: tv_rec.h:420
TVRec::CheckForRecGroupChange
void CheckForRecGroupChange(void)
Check if frontend changed the recording group.
Definition: tv_rec.cpp:2655
ChannelBase::SetChannelByString
virtual bool SetChannelByString(const QString &chan)=0
TVRec::m_internalState
TVState m_internalState
Definition: tv_rec.h:390
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:451
livetvchain.h
DTVSignalMonitor::IgnoreEncrypted
void IgnoreEncrypted(bool ignore)
Definition: dtvsignalmonitor.h:102
TVRec::m_signalEventCmdTimeout
QDateTime m_signalEventCmdTimeout
Definition: tv_rec.h:342
Buffer
Definition: MythExternControl.h:36
DTVSignalMonitor::SetChannel
void SetChannel(int major, int minor)
Definition: dtvsignalmonitor.cpp:196
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
channelgroup.h
DVBDBOptions::m_dvbEitScan
bool m_dvbEitScan
Definition: tv_rec.h:90
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:204
TVRec::m_reachedRecordingDeadline
bool m_reachedRecordingDeadline
Definition: tv_rec.h:348
RecStatus::Recording
@ Recording
Definition: recStatus.h:30
TVRec::GetChannelInfo
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltvid) const
Definition: tv_rec.cpp:3229
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
RecStatus::Inactive
@ Inactive
Definition: recStatus.h:42
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1277
SignalMonitor::AddListener
void AddListener(SignalMonitorListener *listener)
Definition: signalmonitor.cpp:388
mythcorecontext.h
TVRec::GetV4LChannel
V4LChannel * GetV4LChannel(void)
Definition: tv_rec.cpp:1207
TVRec::m_genOpt
GeneralDBOptions m_genOpt
Definition: tv_rec.h:375
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
cardutil.h
ProgramInfo::IsLocal
bool IsLocal(void) const
Definition: programinfo.h:351
TVRec::m_pendingRecLock
QRecursiveMutex m_pendingRecLock
Definition: tv_rec.h:388
TVRec::RingBufferChanged
void RingBufferChanged(MythMediaBuffer *Buffer, RecordingInfo *pginfo, RecordingQuality *recq)
Definition: tv_rec.cpp:3326
JobQueue::AddJobsToMask
static void AddJobsToMask(int jobs, int &mask)
Definition: jobqueue.h:199
TVRec::TuningRestartRecorder
void TuningRestartRecorder(void)
Restarts a stopped recorder or unpauses a paused recorder.
Definition: tv_rec.cpp:4293
TVRec::kSignalMonitoringRate
static constexpr std::chrono::milliseconds kSignalMonitoringRate
How many milliseconds the signal monitor should wait between checks.
Definition: tv_rec.h:437
ChannelBase::CheckChannel
bool CheckChannel(const QString &channum) const
Definition: channelbase.cpp:667
ProgramInfo::QueryAverageHeight
uint QueryAverageHeight(void) const
If present in recording this loads average height of the main video stream from database's stream mar...
Definition: programinfo.cpp:4457
TVRec::SetupDTVSignalMonitor
bool SetupDTVSignalMonitor(bool EITscan)
Tells DTVSignalMonitor what channel to look for.
Definition: tv_rec.cpp:1796
ChannelGroup::GetChannelGroupId
static int GetChannelGroupId(const QString &changroupname)
Definition: channelgroup.cpp:254
TVRec::kFlagAnyRunning
static const uint kFlagAnyRunning
Definition: tv_rec.h:480
RecorderBase::SetNextRecording
void SetNextRecording(const RecordingInfo *ri, MythMediaBuffer *Buffer)
Sets next recording info, to be applied as soon as practical.
Definition: recorderbase.cpp:124
TVRec::SetSignalMonitoringRate
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
Definition: tv_rec.cpp:2068
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:21
PreviewGeneratorQueue::GetPreviewImage
static void GetPreviewImage(const ProgramInfo &pginfo, const QString &token)
Submit a request for the generation of a preview image.
Definition: previewgeneratorqueue.h:89
TVRec::m_dvbOpt
DVBDBOptions m_dvbOpt
Definition: tv_rec.h:376
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
MarkTypes
MarkTypes
Definition: programtypes.h:48
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:78
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
DVBDBOptions
Definition: tv_rec.h:83
GeneralDBOptions::m_videoDev
QString m_videoDev
Definition: tv_rec.h:72
TVRec::kFlagFinishRecording
static const uint kFlagFinishRecording
Definition: tv_rec.h:443
DTVChannel::SetTuningMode
void SetTuningMode(const QString &tuning_mode)
Sets tuning mode: "mpeg", "dvb", "atsc", etc.
Definition: dtvchannel.cpp:87
FireWireDBOptions::m_connection
int m_connection
Definition: tv_rec.h:99
DTVSignalMonitor::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
Definition: dtvsignalmonitor.cpp:258
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:22
BROWSE_SAME
@ BROWSE_SAME
Fetch browse information on current channel and time.
Definition: tv.h:40
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:144
FireWireDBOptions
Definition: tv_rec.h:93
RecordingInfo::AddHistory
void AddHistory(bool resched=true, bool forcedup=false, bool future=false)
Adds recording history, creating "record" it if necessary.
Definition: recordinginfo.cpp:1303
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:834
TVRec::m_signalMonitorCheckCnt
uint m_signalMonitorCheckCnt
Definition: tv_rec.h:347
DTVSignalMonitor::SetRotorTarget
virtual void SetRotorTarget(float)
Sets rotor target pos from 0.0 to 1.0.
Definition: dtvsignalmonitor.h:46
TVRec::kAutoRunProfile
@ kAutoRunProfile
Definition: tv_rec.h:326
RecorderBase::SetVideoFilters
virtual void SetVideoFilters(QString &filters)=0
Tells recorder which filters to use.
TuningRequest::IsOnSameMultiplex
bool IsOnSameMultiplex(void) const
Definition: tv_rec.h:115
TVRec::m_stateFlags
uint m_stateFlags
Definition: tv_rec.h:394
TVRec::WakeEventLoop
void WakeEventLoop(void)
Definition: tv_rec.cpp:231
GeneralDBOptions::m_audioDev
QString m_audioDev
Definition: tv_rec.h:74
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
DTVChannel::GetProgramNumber
int GetProgramNumber(void) const
Returns program number in PAT, -1 if unknown.
Definition: dtvchannel.h:90
LiveTVChain::AppendNewProgram
void AppendNewProgram(ProgramInfo *pginfo, const QString &channum, const QString &inputname, bool discont)
Definition: livetvchain.cpp:61
TVRec::GetState
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:244
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
TVRec::m_signalMonitorDeadline
QDateTime m_signalMonitorDeadline
Definition: tv_rec.h:346
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1845
DVBDBOptions::m_dvbTuningDelay
std::chrono::milliseconds m_dvbTuningDelay
Definition: tv_rec.h:89
PendingInfo::m_doNotAsk
bool m_doNotAsk
Definition: tv_rec.h:139
TVRec::SwitchLiveTVRingBuffer
bool SwitchLiveTVRingBuffer(const QString &channum, bool discont, bool set_rec)
Definition: tv_rec.cpp:4623
tv_rec.h
DTVSignalMonitor
This class is intended to detect the presence of needed tables.
Definition: dtvsignalmonitor.h:14
TVRec::StateIsPlaying
static bool StateIsPlaying(TVState state)
Returns true if we are in any state associated with a player.
Definition: tv_rec.cpp:762
ChannelBase::GetInputID
virtual int GetInputID(void) const
Definition: channelbase.h:67
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
Definition: tvremoteutil.cpp:50
StorageGroup
Definition: storagegroup.h:11
TableID::TVCT
@ TVCT
Definition: mpegtables.h:362
SignalMonitor::Start
virtual void Start()
Start signal monitoring thread.
Definition: signalmonitor.cpp:291
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:98
InputInfo
Definition: inputinfo.h:14
previewgeneratorqueue.h
TVRec::m_lastTuningRequest
TuningRequest m_lastTuningRequest
Definition: tv_rec.h:396
SignalMonitor::SetNotifyFrontend
void SetNotifyFrontend(bool notify)
Enables or disables frontend notification of the current signal value.
Definition: signalmonitor.h:97
TVRec::m_recorderThread
MThread * m_recorderThread
Recorder thread, runs RecorderBase::run().
Definition: tv_rec.h:356
atsctables.h
TVRec::StartedRecording
void StartedRecording(RecordingInfo *curRec)
Inserts a "curRec" into the database.
Definition: tv_rec.cpp:808
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2735
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:37
PendingInfo::m_ask
bool m_ask
Definition: tv_rec.h:138
StandardSetting
Definition: standardsettings.h:29
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:333
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:247
MPEGStreamData::AddListeningPID
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:120
CardUtil::GetInputInfo
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
Definition: cardutil.cpp:1626
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:861
recordingprofile.h
TVRec::TVRec
TVRec(int _inputid)
Performs instance initialization not requiring access to database.
Definition: tv_rec.cpp:84
ChannelBase::GetSourceID
virtual uint GetSourceID(void) const
Definition: channelbase.h:71
CardUtil::IsEITCapable
static bool IsEITCapable(const QString &rawtype)
Definition: cardutil.h:165
TVRec::kFlagAntennaAdjust
static const uint kFlagAntennaAdjust
antenna adjusting mode (LiveTV without recording).
Definition: tv_rec.h:453
TVRec::kFlagExitPlayer
static const uint kFlagExitPlayer
Definition: tv_rec.h:442
StateToString
QString StateToString(TVState state)
Returns a human readable QString representing a TVState.
Definition: tv.cpp:11
DTVChannel
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:33
RecorderBase::GetKeyframePosition
long long GetKeyframePosition(long long desired) const
Returns closest keyframe position before the desired frame.
Definition: recorderbase.cpp:521
SignalMonitor::IsErrored
bool IsErrored(void) const
Definition: signalmonitor.h:87
ProgramInfo::SetRecordingRuleID
void SetRecordingRuleID(uint id)
Definition: programinfo.h:540
TVRec::TuningSignalCheck
MPEGStreamData * TuningSignalCheck(void)
This checks if we have a channel lock.
Definition: tv_rec.cpp:3842
TVRec::~TVRec
~TVRec(void) override
Stops the event and scanning threads and deletes any ChannelBase, RingBuffer, and RecorderBase instan...
Definition: tv_rec.cpp:195
ChannelBase::GetNextChannel
virtual uint GetNextChannel(uint chanid, ChannelChangeDirection direction) const
Definition: channelbase.cpp:201
RecordingProfile
Definition: recordingprofile.h:41
TVRec::m_isPip
bool m_isPip
Definition: tv_rec.h:372
DTVChannel::GetCachedPids
void GetCachedPids(pid_cache_t &pid_cache) const
Returns cached MPEG PIDs for last tuned channel.
Definition: dtvchannel.cpp:97
get_highest_input
static int get_highest_input(void)
Definition: tv_rec.cpp:1257
RecStatus::toString
static QString toString(Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Definition: recStatus.cpp:39
TVRec::SetVideoFiltersForChannel
bool SetVideoFiltersForChannel(uint sourceid, const QString &channum)
Definition: tv_rec.cpp:2393
DTVChannel::GetSuggestedTuningMode
QString GetSuggestedTuningMode(bool is_live_tv) const
Returns suggested tuning mode: "mpeg", "dvb", or "atsc".
Definition: dtvchannel.cpp:57
PendingInfo::m_recordingStart
QDateTime m_recordingStart
Definition: tv_rec.h:135
TuningRequest::m_channel
QString m_channel
Definition: tv_rec.h:120
TVRec::m_fwOpt
FireWireDBOptions m_fwOpt
Definition: tv_rec.h:377
TVRec::HasFlags
bool HasFlags(uint f) const
Definition: tv_rec.h:288
TVRec::GetDTVRecorder
DTVRecorder * GetDTVRecorder(void)
Definition: tv_rec.cpp:1183
ChannelUtil::GetChanNum
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
Definition: channelutil.cpp: