MythTV  master
mythcommflag.cpp
Go to the documentation of this file.
1 
2 #if defined ANDROID && __ANDROID_API__ < 24
3 // ftello and fseeko do not exist in android before api level 24
4 #define ftello ftell
5 #define fseeko fseek
6 #endif
7 
8 // POSIX headers
9 #include <unistd.h>
10 
11 // C++ headers
12 #include <cmath>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <ctime>
16 #include <fstream>
17 #include <iostream>
18 #include <string>
19 
20 // Qt headers
21 #include <QCoreApplication>
22 #include <QDir>
23 #include <QEvent>
24 #include <QString>
25 #include <QtGlobal>
26 
27 // MythTV headers
28 #include "libmyth/mythcontext.h"
30 #include "libmythbase/exitcodes.h"
31 #include "libmythbase/mythdate.h"
32 #include "libmythbase/mythdb.h"
37 #include "libmythbase/remotefile.h"
38 #include "libmythbase/remoteutil.h"
41 #include "libmythtv/jobqueue.h"
44 #include "libmythtv/tvremoteutil.h"
45 
47 
48 // Commercial Flagging headers
49 #include "CommDetectorBase.h"
50 #include "CommDetectorFactory.h"
51 #include "CustomEventRelayer.h"
52 #include "SlotRelayer.h"
53 
54 #define LOC QString("MythCommFlag: ")
55 #define LOC_WARN QString("MythCommFlag, Warning: ")
56 #define LOC_ERR QString("MythCommFlag, Error: ")
57 
58 namespace
59 {
60  void cleanup()
61  {
62  delete gContext;
63  gContext = nullptr;
65  }
66 }
67 
68 int quiet = 0;
69 bool progress = true;
70 bool force = false;
71 
73 
74 bool watchingRecording = false;
78 int recorderNum = -1;
79 
80 int jobID = -1;
81 int lastCmd = -1;
82 
83 static QMap<QString,SkipType> *init_skip_types();
84 QMap<QString,SkipType> *skipTypes = init_skip_types();
85 
86 static QMap<QString,SkipType> *init_skip_types(void)
87 {
88  auto *tmp = new QMap<QString,SkipType>;
89  (*tmp)["commfree"] = COMM_DETECT_COMMFREE;
90  (*tmp)["uninit"] = COMM_DETECT_UNINIT;
91  (*tmp)["off"] = COMM_DETECT_OFF;
92  (*tmp)["blank"] = COMM_DETECT_BLANKS;
93  (*tmp)["blanks"] = COMM_DETECT_BLANKS;
94  (*tmp)["scene"] = COMM_DETECT_SCENE;
95  (*tmp)["blankscene"] = COMM_DETECT_BLANK_SCENE;
96  (*tmp)["blank_scene"] = COMM_DETECT_BLANK_SCENE;
97  (*tmp)["logo"] = COMM_DETECT_LOGO;
98  (*tmp)["all"] = COMM_DETECT_ALL;
99  (*tmp)["d2"] = COMM_DETECT_2;
100  (*tmp)["d2_logo"] = COMM_DETECT_2_LOGO;
101  (*tmp)["d2_blank"] = COMM_DETECT_2_BLANK;
102  (*tmp)["d2_scene"] = COMM_DETECT_2_SCENE;
103  (*tmp)["d2_all"] = COMM_DETECT_2_ALL;
104  return tmp;
105 }
106 
108 {
111 };
113 
114 static QMap<QString,OutputMethod> *init_output_types();
115 QMap<QString,OutputMethod> *outputTypes = init_output_types();
116 
117 static QMap<QString,OutputMethod> *init_output_types(void)
118 {
119  auto *tmp = new QMap<QString,OutputMethod>;
120  (*tmp)["essentials"] = kOutputMethodEssentials;
121  (*tmp)["full"] = kOutputMethodFull;
122  return tmp;
123 }
124 
125 static QString get_filename(ProgramInfo *program_info)
126 {
127  QString filename = program_info->GetPathname();
128  if (!QFile::exists(filename))
129  filename = program_info->GetPlaybackURL(true);
130  return filename;
131 }
132 
133 static int QueueCommFlagJob(uint chanid, const QDateTime& starttime, bool rebuild)
134 {
135  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
136  const ProgramInfo pginfo(chanid, starttime);
137 
138  if (!pginfo.GetChanID())
139  {
140  if (progress)
141  {
142  QString tmp = QString(
143  "Unable to find program info for chanid %1 @ %2")
144  .arg(chanid).arg(startstring);
145  std::cerr << tmp.toLocal8Bit().constData() << std::endl;
146  }
148  }
149 
150  if (cmdline.toBool("dryrun"))
151  {
152  QString tmp = QString("Job have been queued for chanid %1 @ %2")
153  .arg(chanid).arg(startstring);
154  std::cerr << tmp.toLocal8Bit().constData() << std::endl;
155  return GENERIC_EXIT_OK;
156  }
157 
158  bool result = JobQueue::QueueJob(JOB_COMMFLAG,
159  pginfo.GetChanID(), pginfo.GetRecordingStartTime(), "", "", "",
160  rebuild ? JOB_REBUILD : 0, JOB_QUEUED, QDateTime());
161 
162  if (result)
163  {
164  if (progress)
165  {
166  QString tmp = QString("Job Queued for chanid %1 @ %2")
167  .arg(chanid).arg(startstring);
168  std::cerr << tmp.toLocal8Bit().constData() << std::endl;
169  }
170  return GENERIC_EXIT_OK;
171  }
172 
173  if (progress)
174  {
175  QString tmp = QString("Error queueing job for chanid %1 @ %2")
176  .arg(chanid).arg(startstring);
177  std::cerr << tmp.toLocal8Bit().constData() << std::endl;
178  }
179  return GENERIC_EXIT_DB_ERROR;
180 }
181 
182 static int CopySkipListToCutList(uint chanid, const QDateTime& starttime)
183 {
184  frm_dir_map_t cutlist;
185  frm_dir_map_t::const_iterator it;
186 
187  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
188  const ProgramInfo pginfo(chanid, starttime);
189 
190  if (!pginfo.GetChanID())
191  {
192  LOG(VB_GENERAL, LOG_ERR,
193  QString("No program data exists for channel %1 at %2")
194  .arg(chanid).arg(startstring));
196  }
197 
198  pginfo.QueryCommBreakList(cutlist);
199  for (it = cutlist.cbegin(); it != cutlist.cend(); ++it)
200  {
201  if (*it == MARK_COMM_START)
202  cutlist[it.key()] = MARK_CUT_START;
203  else
204  cutlist[it.key()] = MARK_CUT_END;
205  }
206  pginfo.SaveCutList(cutlist);
207 
208  return GENERIC_EXIT_OK;
209 }
210 
211 static int ClearSkipList(uint chanid, const QDateTime& starttime)
212 {
213  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
214  const ProgramInfo pginfo(chanid, starttime);
215 
216  if (!pginfo.GetChanID())
217  {
218  LOG(VB_GENERAL, LOG_ERR,
219  QString("No program data exists for channel %1 at %2")
220  .arg(chanid).arg(startstring));
222  }
223 
224  frm_dir_map_t skiplist;
225  pginfo.SaveCommBreakList(skiplist);
226 
227  LOG(VB_GENERAL, LOG_NOTICE, "Commercial skip list cleared");
228 
229  return GENERIC_EXIT_OK;
230 }
231 
232 static int SetCutList(uint chanid, const QDateTime& starttime, QString newCutList)
233 {
234  frm_dir_map_t cutlist;
235 
236  newCutList.remove(" ");
237 
238 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
239  QStringList tokens = newCutList.split(",", QString::SkipEmptyParts);
240 #else
241  QStringList tokens = newCutList.split(",", Qt::SkipEmptyParts);
242 #endif
243 
244  for (const QString& token : qAsConst(tokens))
245  {
246 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
247  QStringList cutpair = token.split("-", QString::SkipEmptyParts);
248 #else
249  QStringList cutpair = token.split("-", Qt::SkipEmptyParts);
250 #endif
251  cutlist[cutpair[0].toInt()] = MARK_CUT_START;
252  cutlist[cutpair[1].toInt()] = MARK_CUT_END;
253  }
254 
255  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
256  const ProgramInfo pginfo(chanid, starttime);
257 
258  if (!pginfo.GetChanID())
259  {
260  LOG(VB_GENERAL, LOG_ERR,
261  QString("No program data exists for channel %1 at %2")
262  .arg(chanid).arg(startstring));
264  }
265 
266  pginfo.SaveCutList(cutlist);
267 
268  LOG(VB_GENERAL, LOG_NOTICE, QString("Cutlist set to: %1").arg(newCutList));
269 
270  return GENERIC_EXIT_OK;
271 }
272 
273 static int GetMarkupList(const QString& list, uint chanid, const QDateTime& starttime)
274 {
275  frm_dir_map_t cutlist;
276  frm_dir_map_t::const_iterator it;
277  QString result;
278 
279  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
280  const ProgramInfo pginfo(chanid, starttime);
281 
282  if (!pginfo.GetChanID())
283  {
284  LOG(VB_GENERAL, LOG_ERR,
285  QString("No program data exists for channel %1 at %2")
286  .arg(chanid).arg(startstring));
288  }
289 
290  if (list == "cutlist")
291  pginfo.QueryCutList(cutlist);
292  else
293  pginfo.QueryCommBreakList(cutlist);
294 
295  uint64_t lastStart = 0;
296  for (it = cutlist.cbegin(); it != cutlist.cend(); ++it)
297  {
298  if ((*it == MARK_COMM_START) ||
299  (*it == MARK_CUT_START))
300  {
301  if (!result.isEmpty())
302  result += ",";
303  lastStart = it.key();
304  result += QString("%1-").arg(lastStart);
305  }
306  else
307  {
308  if (result.isEmpty())
309  result += "0-";
310  result += QString("%1").arg(it.key());
311  }
312  }
313 
314  if (result.endsWith('-'))
315  {
316  uint64_t lastFrame = pginfo.QueryLastFrameInPosMap() + 60;
317  if (lastFrame > lastStart)
318  result += QString("%1").arg(lastFrame);
319  }
320 
321  if (list == "cutlist")
322  std::cout << QString("Cutlist: %1\n").arg(result).toLocal8Bit().constData();
323  else
324  {
325  std::cout << QString("Commercial Skip List: %1\n")
326  .arg(result).toLocal8Bit().constData();
327  }
328 
329  return GENERIC_EXIT_OK;
330 }
331 
333  std::ostream &output, const frm_dir_map_t &commercialBreakList)
334 {
335  if (progress)
336  output << "----------------------------" << std::endl;
337 
338  if (commercialBreakList.empty())
339  {
340  if (progress)
341  output << "No breaks" << std::endl;
342  }
343  else
344  {
345  frm_dir_map_t::const_iterator it = commercialBreakList.begin();
346  for (; it != commercialBreakList.end(); ++it)
347  {
348  output << "framenum: " << it.key() << "\tmarktype: " << *it
349  << std::endl;
350  }
351  }
352 
353  if (progress)
354  output << "----------------------------" << std::endl;
355 }
356 
358  const ProgramInfo *program_info,
359  const frm_dir_map_t &commBreakList,
360  uint64_t frame_count,
361  const CommDetectorBase *commDetect,
362  const QString &output_filename)
363 {
364  if (output_filename.isEmpty())
365  return;
366 
367  std::ostream *out = &std::cout;
368  if (output_filename != "-")
369  {
370  QByteArray tmp = output_filename.toLocal8Bit();
371  out = new std::fstream(tmp.constData(), std::ios::app | std::ios::out );
372  }
373 
374  if (progress)
375  {
376  QString tmp = "";
377  if (program_info->GetChanID())
378  {
379  tmp = QString("commercialBreakListFor: %1 on %2 @ %3")
380  .arg(program_info->GetTitle())
381  .arg(program_info->GetChanID())
382  .arg(program_info->GetRecordingStartTime(MythDate::ISODate));
383  }
384  else
385  {
386  tmp = QString("commercialBreakListFor: %1")
387  .arg(program_info->GetPathname());
388  }
389 
390  const QByteArray tmp2 = tmp.toLocal8Bit();
391  *out << tmp2.constData() << std::endl;
392 
393  if (frame_count)
394  *out << "totalframecount: " << frame_count << std::endl;
395  }
396 
397  if (commDetect)
398  commDetect->PrintFullMap(*out, &commBreakList, progress);
399  else
400  streamOutCommercialBreakList(*out, commBreakList);
401 
402  if (out != &std::cout)
403  delete out;
404 }
405 
406 static void commDetectorBreathe()
407 {
408  //this is connected to the commdetectors breathe signal so we get a chance
409  //while its busy to see if the user already told us to stop.
410  qApp->processEvents();
411 
412  if (jobID != -1)
413  {
414  int curCmd = JobQueue::GetJobCmd(jobID);
415  if (curCmd == lastCmd)
416  return;
417 
418  switch (curCmd)
419  {
420  case JOB_STOP:
421  {
422  commDetector->stop();
423  break;
424  }
425  case JOB_PAUSE:
426  {
427  JobQueue::ChangeJobStatus(jobID, JOB_PAUSED,
428  QCoreApplication::translate("(mythcommflag)",
429  "Paused", "Job status"));
430  commDetector->pause();
431  break;
432  }
433  case JOB_RESUME:
434  {
435  JobQueue::ChangeJobStatus(jobID, JOB_RUNNING,
436  QCoreApplication::translate("(mythcommflag)",
437  "Running", "Job status"));
438  commDetector->resume();
439  break;
440  }
441  }
442  }
443 }
444 
445 static void commDetectorStatusUpdate(const QString& status)
446 {
447  if (jobID != -1)
448  {
449  JobQueue::ChangeJobStatus(jobID, JOB_RUNNING, status);
451  }
452 }
453 
455 {
456  frm_dir_map_t newCommercialMap;
457  commDetector->GetCommercialBreakList(newCommercialMap);
458 
459  QString message = "COMMFLAG_UPDATE ";
460  message += global_program_info->MakeUniqueKey();
461 
462  for (auto it = newCommercialMap.begin();
463  it != newCommercialMap.end(); ++it)
464  {
465  if (it != newCommercialMap.begin())
466  message += ",";
467  else
468  message += " ";
469  message += QString("%1:%2").arg(it.key())
470  .arg(*it);
471  }
472 
473  LOG(VB_COMMFLAG, LOG_INFO,
474  QString("mythcommflag sending update: %1").arg(message));
475 
476  gCoreContext->SendMessage(message);
477 }
478 
479 static void incomingCustomEvent(QEvent* e)
480 {
481  if (e->type() == MythEvent::MythEventMessage)
482  {
483  auto *me = dynamic_cast<MythEvent *>(e);
484  if (me == nullptr)
485  return;
486 
487  QString message = me->Message();
488 
489  message = message.simplified();
490 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
491  QStringList tokens = message.split(" ", QString::SkipEmptyParts);
492 #else
493  QStringList tokens = message.split(" ", Qt::SkipEmptyParts);
494 #endif
495 
496  LOG(VB_COMMFLAG, LOG_INFO,
497  QString("mythcommflag: Received Event: '%1'") .arg(message));
498 
499  if ((watchingRecording) && (tokens.size() >= 3) &&
500  (tokens[0] == "DONE_RECORDING"))
501  {
502  int cardnum = tokens[1].toInt();
503  int filelen = tokens[2].toInt();
504 
505  message = QString("mythcommflag: Received a "
506  "DONE_RECORDING event for card %1. ")
507  .arg(cardnum);
508 
509  if (recorderNum != -1 && cardnum == recorderNum)
510  {
512  watchingRecording = false;
513  message += "Informed CommDetector that recording has finished.";
514  LOG(VB_COMMFLAG, LOG_INFO, message);
515  }
516  }
517 
518  if ((tokens.size() >= 2) && (tokens[0] == "COMMFLAG_REQUEST"))
519  {
520  uint chanid = 0;
521  QDateTime recstartts;
522  ProgramInfo::ExtractKey(tokens[1], chanid, recstartts);
523 
524  message = QString("mythcommflag: Received a "
525  "COMMFLAG_REQUEST event for chanid %1 @ %2. ")
526  .arg(chanid).arg(recstartts.toString(Qt::ISODate));
527 
528  if ((global_program_info->GetChanID() == chanid) &&
529  (global_program_info->GetRecordingStartTime() == recstartts))
530  {
532  message += "Requested CommDetector to generate new break list.";
533  LOG(VB_COMMFLAG, LOG_INFO, message);
534  }
535  }
536  }
537 }
538 
539 static int DoFlagCommercials(
540  ProgramInfo *program_info,
541  bool showPercentage, bool fullSpeed, int jobid,
542  MythCommFlagPlayer* cfp, SkipType commDetectMethod,
543  const QString &outputfilename, bool useDB)
544 {
546  commDetectMethod, showPercentage,
547  fullSpeed, cfp,
548  program_info->GetChanID(),
549  program_info->GetScheduledStartTime(),
550  program_info->GetScheduledEndTime(),
551  program_info->GetRecordingStartTime(),
552  program_info->GetRecordingEndTime(), useDB);
553 
554  if (jobid > 0)
555  LOG(VB_COMMFLAG, LOG_INFO,
556  QString("mythcommflag processing JobID %1").arg(jobid));
557 
558  if (useDB)
559  program_info->SaveCommFlagged(COMM_FLAG_PROCESSING);
560 
561  auto *cer = new CustomEventRelayer(incomingCustomEvent);
562  auto *a = new SlotRelayer(commDetectorBreathe);
563  auto *b = new SlotRelayer(commDetectorStatusUpdate);
565  QObject::connect(commDetector, &CommDetectorBase::breathe,
566  a, qOverload<>(&SlotRelayer::relay));
567  QObject::connect(commDetector, &CommDetectorBase::statusUpdate,
568  b, qOverload<const QString&>(&SlotRelayer::relay));
570  c, qOverload<>(&SlotRelayer::relay));
571 
572  if (useDB)
573  {
574  LOG(VB_COMMFLAG, LOG_INFO,
575  "mythcommflag sending COMMFLAG_START notification");
576  QString message = "COMMFLAG_START ";
577  message += program_info->MakeUniqueKey();
578  gCoreContext->SendMessage(message);
579  }
580 
581  bool result = commDetector->go();
582  int comms_found = 0;
583 
584  if (result)
585  {
586  cfp->SaveTotalDuration();
587 
588  frm_dir_map_t commBreakList;
589  commDetector->GetCommercialBreakList(commBreakList);
590  comms_found = commBreakList.size() / 2;
591 
592  if (useDB)
593  {
594  program_info->SaveMarkupFlag(MARK_UPDATED_CUT);
595  program_info->SaveCommBreakList(commBreakList);
596  program_info->SaveCommFlagged(COMM_FLAG_DONE);
597  }
598 
600  program_info, commBreakList, cfp->GetTotalFrameCount(),
602  outputfilename);
603  }
604  else
605  {
606  if (useDB)
607  program_info->SaveCommFlagged(COMM_FLAG_NOT_FLAGGED);
608  }
609 
611  commDetector = nullptr;
612  sleep(1);
613  tmp->deleteLater();
614 
615  cer->deleteLater();
616  c->deleteLater();
617  b->deleteLater();
618  a->deleteLater();
619 
620  return comms_found;
621 }
622 
623 static qint64 GetFileSize(ProgramInfo *program_info)
624 {
625  QString filename = get_filename(program_info);
626  qint64 size = -1;
627 
628  if (filename.startsWith("myth://"))
629  {
630  RemoteFile remotefile(filename, false, false, 0s);
631  size = remotefile.GetFileSize();
632  }
633  else
634  {
635  QFile file(filename);
636  if (file.exists())
637  {
638  size = file.size();
639  }
640  }
641 
642  return size;
643 }
644 
645 static bool DoesFileExist(ProgramInfo *program_info)
646 {
647  QString filename = get_filename(program_info);
648  qint64 size = GetFileSize(program_info);
649 
650  if (size < 0)
651  {
652  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find file %1, aborting.")
653  .arg(filename));
654  return false;
655  }
656 
657  if (size == 0)
658  {
659  LOG(VB_GENERAL, LOG_ERR, QString("File %1 is zero-byte, aborting.")
660  .arg(filename));
661  return false;
662  }
663 
664  return true;
665 }
666 
667 static void UpdateFileSize(ProgramInfo *program_info)
668 {
669  qint64 size = GetFileSize(program_info);
670 
671  if (size != (qint64)program_info->GetFilesize())
672  program_info->SaveFilesize(size);
673 }
674 
675 static bool IsMarked(uint chanid, const QDateTime& starttime)
676 {
677  MSqlQuery mark_query(MSqlQuery::InitCon());
678  mark_query.prepare("SELECT commflagged, count(rm.type) "
679  "FROM recorded r "
680  "LEFT JOIN recordedmarkup rm ON "
681  "( r.chanid = rm.chanid AND "
682  "r.starttime = rm.starttime AND "
683  "type in (:MARK_START,:MARK_END)) "
684  "WHERE r.chanid = :CHANID AND "
685  "r.starttime = :STARTTIME "
686  "GROUP BY COMMFLAGGED;");
687  mark_query.bindValue(":MARK_START", MARK_COMM_START);
688  mark_query.bindValue(":MARK_END", MARK_COMM_END);
689  mark_query.bindValue(":CHANID", chanid);
690  mark_query.bindValue(":STARTTIME", starttime);
691 
692  if (mark_query.exec() && mark_query.isActive() &&
693  mark_query.size() > 0)
694  {
695  if (mark_query.next())
696  {
697  int flagStatus = mark_query.value(0).toInt();
698  int marksFound = mark_query.value(1).toInt();
699 
700  QString flagStatusStr = "UNKNOWN";
701  switch (flagStatus) {
703  flagStatusStr = "Not Flagged";
704  break;
705  case COMM_FLAG_DONE:
706  flagStatusStr = QString("Flagged with %1 breaks")
707  .arg(marksFound / 2);
708  break;
710  flagStatusStr = "Flagging";
711  break;
712  case COMM_FLAG_COMMFREE:
713  flagStatusStr = "Commercial Free";
714  break;
715  }
716 
717  LOG(VB_COMMFLAG, LOG_INFO,
718  QString("Status for chanid %1 @ %2 is '%3'")
719  .arg(QString::number(chanid),
720  starttime.toString(Qt::ISODate),
721  flagStatusStr));
722 
723  if ((flagStatus == COMM_FLAG_NOT_FLAGGED) && (marksFound == 0))
724  return false;
725  }
726  }
727  return true;
728 }
729 
730 static int FlagCommercials(ProgramInfo *program_info, int jobid,
731  const QString &outputfilename, bool useDB, bool fullSpeed)
732 {
733  global_program_info = program_info;
734 
735  int breaksFound = 0;
736 
737  // configure commercial detection method
738  SkipType commDetectMethod = (SkipType)gCoreContext->GetNumSetting(
739  "CommercialSkipMethod", COMM_DETECT_ALL);
740 
741  if (cmdline.toBool("commmethod"))
742  {
743  // pull commercial detection method from command line
744  QString commmethod = cmdline.toString("commmethod");
745 
746  // assume definition as integer value
747  bool ok = true;
748  commDetectMethod = (SkipType) commmethod.toInt(&ok);
749  if (!ok)
750  {
751  // not an integer, attempt comma separated list
752  commDetectMethod = COMM_DETECT_UNINIT;
753 
754 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
755  QStringList list = commmethod.split(",", QString::SkipEmptyParts);
756 #else
757  QStringList list = commmethod.split(",", Qt::SkipEmptyParts);
758 #endif
759  for (const auto & it : qAsConst(list))
760  {
761  QString val = it.toLower();
762  if (val == "off")
763  {
764  commDetectMethod = COMM_DETECT_OFF;
765  break;
766  }
767 
768  if (!skipTypes->contains(val))
769  {
770  std::cerr << "Failed to decode --method option '"
771  << val.toLatin1().constData()
772  << "'" << std::endl;
774  }
775 
776  if (commDetectMethod == COMM_DETECT_UNINIT) {
777  commDetectMethod = skipTypes->value(val);
778  } else {
779  commDetectMethod = (SkipType) ((int)commDetectMethod
780  | (int)skipTypes->value(val));
781  }
782  }
783 
784  }
785  if (commDetectMethod == COMM_DETECT_UNINIT)
787  }
788  else if (useDB)
789  {
790  // if not manually specified, and we have a database to access
791  // pull the commflag type from the channel
792  MSqlQuery query(MSqlQuery::InitCon());
793  query.prepare("SELECT commmethod FROM channel "
794  "WHERE chanid = :CHANID;");
795  query.bindValue(":CHANID", program_info->GetChanID());
796 
797  if (!query.exec())
798  {
799  // if the query fails, return with an error
800  commDetectMethod = COMM_DETECT_UNINIT;
801  MythDB::DBError("FlagCommercials", query);
802  }
803  else if (query.next())
804  {
805  commDetectMethod = (SkipType)query.value(0).toInt();
806  if (commDetectMethod == COMM_DETECT_COMMFREE)
807  {
808  // if the channel is commercial free, drop to the default instead
809  commDetectMethod = (SkipType)gCoreContext->GetNumSetting(
810  "CommercialSkipMethod", COMM_DETECT_ALL);
811  LOG(VB_COMMFLAG, LOG_INFO,
812  QString("Chanid %1 is marked as being Commercial Free, "
813  "we will use the default commercial detection "
814  "method").arg(program_info->GetChanID()));
815  }
816  else if (commDetectMethod == COMM_DETECT_UNINIT)
817  {
818  // no value set, so use the database default
819  commDetectMethod = (SkipType)gCoreContext->GetNumSetting(
820  "CommercialSkipMethod", COMM_DETECT_ALL);
821  }
822  LOG(VB_COMMFLAG, LOG_INFO,
823  QString("Using method: %1 from channel %2")
824  .arg(commDetectMethod).arg(program_info->GetChanID()));
825  }
826 
827  }
828  else if (!useDB)
829  {
830  // default to a cheaper method for debugging purposes
831  commDetectMethod = COMM_DETECT_BLANK;
832  }
833 
834  // if selection has failed, or intentionally disabled, drop out
835  if (commDetectMethod == COMM_DETECT_UNINIT)
836  return GENERIC_EXIT_NOT_OK;
837  if (commDetectMethod == COMM_DETECT_OFF)
838  return GENERIC_EXIT_OK;
839 
840  recorder = nullptr;
841 
842 /*
843  * is there a purpose to this not fulfilled by --getskiplist?
844  if (onlyDumpDBCommercialBreakList)
845  {
846  frm_dir_map_t commBreakList;
847  program_info->QueryCommBreakList(commBreakList);
848 
849  print_comm_flag_output(program_info, commBreakList,
850  0, nullptr, outputfilename);
851 
852  global_program_info = nullptr;
853  return GENERIC_EXIT_OK;
854  }
855 */
856 
857  if (!DoesFileExist(program_info))
858  {
859  LOG(VB_GENERAL, LOG_ERR,
860  "Unable to find file in defined storage paths.");
862  }
863 
864  QString filename = get_filename(program_info);
865 
867  if (!tmprbuf)
868  {
869  LOG(VB_GENERAL, LOG_ERR,
870  QString("Unable to create RingBuffer for %1").arg(filename));
871  global_program_info = nullptr;
873  }
874 
875  if (useDB)
876  {
878  {
879  LOG(VB_GENERAL, LOG_ERR, "Unable to open commflag DB connection");
880  delete tmprbuf;
881  global_program_info = nullptr;
882  return GENERIC_EXIT_DB_ERROR;
883  }
884  }
885 
886  auto flags = static_cast<PlayerFlags>(kAudioMuted | kVideoIsNull | kNoITV);
887 
888  int flagfast = gCoreContext->GetNumSetting("CommFlagFast", 0);
889  if (flagfast)
890  {
891  // Note: These additional flags replicate the intent of the original
892  // commit that enabled lowres support - but I'm not sure why it requires
893  // single threaded decoding - which surely slows everything down? Though
894  // there is probably no profile to enable multi-threaded decoding anyway.
895  LOG(VB_GENERAL, LOG_INFO, "Enabling experimental flagging speedup (low resolution)");
896  flags = static_cast<PlayerFlags>(flags | kDecodeLowRes | kDecodeSingleThreaded | kDecodeNoLoopFilter);
897  }
898 
899  // blank detector needs to be only sample center for this optimization.
900  if (flagfast && ((COMM_DETECT_BLANKS == commDetectMethod) ||
901  (COMM_DETECT_2_BLANK == commDetectMethod)))
902  {
903  flags = static_cast<PlayerFlags>(flags | kDecodeFewBlocks);
904  }
905 
906  auto *ctx = new PlayerContext(kFlaggerInUseID);
907  auto *cfp = new MythCommFlagPlayer(ctx, flags);
908  ctx->SetPlayingInfo(program_info);
909  ctx->SetRingBuffer(tmprbuf);
910  ctx->SetPlayer(cfp);
911 
912  if (useDB)
913  {
914  if (program_info->GetRecordingEndTime() > MythDate::current())
915  {
917 
918  recorder = RemoteGetExistingRecorder(program_info);
919  if (recorder && (recorder->GetRecorderNumber() != -1))
920  {
922  watchingRecording = true;
923  ctx->SetRecorder(recorder);
924 
925  LOG(VB_COMMFLAG, LOG_INFO,
926  QString("mythcommflag will flag recording "
927  "currently in progress on cardid %1")
928  .arg(recorderNum));
929  }
930  else
931  {
932  recorderNum = -1;
933  watchingRecording = false;
934 
935  LOG(VB_GENERAL, LOG_ERR,
936  "Unable to find active recorder for this "
937  "recording, realtime flagging will not be enabled.");
938  }
939  cfp->SetWatchingRecording(watchingRecording);
940  }
941  }
942 
943  // TODO: Add back insertion of job if not in jobqueue
944 
945  breaksFound = DoFlagCommercials(
946  program_info, progress, fullSpeed, jobid,
947  cfp, commDetectMethod, outputfilename, useDB);
948 
949  if (progress)
950  std::cerr << breaksFound << "\n";
951 
952  LOG(VB_GENERAL, LOG_NOTICE, QString("Finished, %1 break(s) found.")
953  .arg(breaksFound));
954 
955  delete ctx;
956  global_program_info = nullptr;
957 
958  return breaksFound;
959 }
960 
961 static int FlagCommercials( uint chanid, const QDateTime &starttime,
962  int jobid, const QString &outputfilename,
963  bool fullSpeed )
964 {
965  QString startstring = MythDate::toString(starttime, MythDate::kFilename);
966  ProgramInfo pginfo(chanid, starttime);
967 
968  if (!pginfo.GetChanID())
969  {
970  LOG(VB_GENERAL, LOG_ERR,
971  QString("No program data exists for channel %1 at %2")
972  .arg(chanid).arg(startstring));
974  }
975 
976  if (!force && JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo))
977  {
978  if (progress)
979  {
980  std::cerr << "IN USE\n";
981  std::cerr << " "
982  "(the program is already being flagged elsewhere)\n";
983  }
984  LOG(VB_GENERAL, LOG_ERR, "Program is already being flagged elsewhere");
985  return GENERIC_EXIT_IN_USE;
986  }
987 
988 
989  if (progress)
990  {
991  std::cerr << "MythTV Commercial Flagger, flagging commercials for:" << std::endl;
992  if (pginfo.GetSubtitle().isEmpty())
993  std::cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << std::endl;
994  else
995  std::cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << " - "
996  << pginfo.GetSubtitle().toLocal8Bit().constData() << std::endl;
997  }
998 
999  return FlagCommercials(&pginfo, jobid, outputfilename, true, fullSpeed);
1000 }
1001 
1002 static int FlagCommercials(const QString& filename, int jobid,
1003  const QString &outputfilename, bool useDB,
1004  bool fullSpeed)
1005 {
1006 
1007  if (progress)
1008  {
1009  std::cerr << "MythTV Commercial Flagger, flagging commercials for:" << std::endl
1010  << " " << filename.toLatin1().constData() << std::endl;
1011  }
1012 
1013  ProgramInfo pginfo(filename);
1014  return FlagCommercials(&pginfo, jobid, outputfilename, useDB, fullSpeed);
1015 }
1016 
1017 static int RebuildSeekTable(ProgramInfo *pginfo, int jobid, bool writefile = false)
1018 {
1019  QString filename = get_filename(pginfo);
1020 
1021  if (!DoesFileExist(pginfo))
1022  {
1023  // file not found on local filesystem
1024  // assume file is in Video storage group on local backend
1025  // and try again
1026 
1027  filename = QString("myth://Videos@%1/%2")
1028  .arg(gCoreContext->GetHostName(), filename);
1029  pginfo->SetPathname(filename);
1030  if (!DoesFileExist(pginfo))
1031  {
1032  LOG(VB_GENERAL, LOG_ERR,
1033  QString("Unable to find file in defined storage "
1034  "paths for JobQueue ID# %1.").arg(jobid));
1036  }
1037  }
1038 
1039  // Update the file size since mythcommflag --rebuild is often used in user
1040  // scripts after transcoding or other size-changing operations
1041  UpdateFileSize(pginfo);
1042 
1044  if (!tmprbuf)
1045  {
1046  LOG(VB_GENERAL, LOG_ERR,
1047  QString("Unable to create RingBuffer for %1").arg(filename));
1049  }
1050 
1051  auto *ctx = new PlayerContext(kFlaggerInUseID);
1052  auto *cfp = new MythCommFlagPlayer(ctx, (PlayerFlags)(kAudioMuted | kVideoIsNull |
1053  kDecodeNoDecode | kNoITV));
1054 
1055  ctx->SetPlayingInfo(pginfo);
1056  ctx->SetRingBuffer(tmprbuf);
1057  ctx->SetPlayer(cfp);
1058 
1059  if (progress)
1060  {
1061  QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1062  std::cerr << "Rebuild started at " << qPrintable(time) << std::endl;
1063  }
1064 
1065  if (writefile)
1067  cfp->RebuildSeekTable(progress);
1068  if (writefile)
1070 
1071  if (progress)
1072  {
1073  QString time = QDateTime::currentDateTime().toString(Qt::TextDate);
1074  std::cerr << "Rebuild completed at " << qPrintable(time) << std::endl;
1075  }
1076 
1077  delete ctx;
1078 
1079  return GENERIC_EXIT_OK;
1080 }
1081 
1082 static int RebuildSeekTable(const QString& filename, int jobid, bool writefile = false)
1083 {
1084  if (progress)
1085  {
1086  std::cerr << "MythTV Commercial Flagger, building seek table for:" << std::endl
1087  << " " << filename.toLatin1().constData() << std::endl;
1088  }
1089  ProgramInfo pginfo(filename);
1090  return RebuildSeekTable(&pginfo, jobid, writefile);
1091 }
1092 
1093 static int RebuildSeekTable(uint chanid, const QDateTime& starttime, int jobid, bool writefile = false)
1094 {
1095  ProgramInfo pginfo(chanid, starttime);
1096  if (progress)
1097  {
1098  std::cerr << "MythTV Commercial Flagger, building seek table for:" << std::endl;
1099  if (pginfo.GetSubtitle().isEmpty())
1100  std::cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << std::endl;
1101  else
1102  std::cerr << " " << pginfo.GetTitle().toLocal8Bit().constData() << " - "
1103  << pginfo.GetSubtitle().toLocal8Bit().constData() << std::endl;
1104  }
1105  return RebuildSeekTable(&pginfo, jobid, writefile);
1106 }
1107 
1108 int main(int argc, char *argv[])
1109 {
1110  int result = GENERIC_EXIT_OK;
1111 
1112 // QString allStart = "19700101000000";
1113 // QString allEnd = MythDate::current().toString("yyyyMMddhhmmss");
1114  int jobType = JOB_NONE;
1115 
1116  if (!cmdline.Parse(argc, argv))
1117  {
1118  cmdline.PrintHelp();
1120  }
1121 
1122  if (cmdline.toBool("showhelp"))
1123  {
1124  cmdline.PrintHelp();
1125  return GENERIC_EXIT_OK;
1126  }
1127 
1128  if (cmdline.toBool("showversion"))
1129  {
1131  return GENERIC_EXIT_OK;
1132  }
1133 
1134  QCoreApplication a(argc, argv);
1135  QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHCOMMFLAG);
1136  int retval = cmdline.ConfigureLogging("general",
1137  !cmdline.toBool("noprogress"));
1138  if (retval != GENERIC_EXIT_OK)
1139  return retval;
1140 
1141  CleanupGuard callCleanup(cleanup);
1142 
1143 #ifndef _WIN32
1145 #endif
1146 
1148  if (!gContext->Init( false, /*use gui*/
1149  false, /*prompt for backend*/
1150  false, /*bypass auto discovery*/
1151  cmdline.toBool("skipdb"))) /*ignoreDB*/
1152  {
1153  LOG(VB_GENERAL, LOG_EMERG, "Failed to init MythContext, exiting.");
1155  }
1157 
1158  MythTranslation::load("mythfrontend");
1159 
1160  if (cmdline.toBool("outputmethod"))
1161  {
1162  QString om = cmdline.toString("outputmethod");
1163  if (outputTypes->contains(om))
1164  outputMethod = outputTypes->value(om);
1165  }
1166 
1167  if (cmdline.toBool("chanid") && cmdline.toBool("starttime"))
1168  {
1169  // operate on a recording in the database
1170  uint chanid = cmdline.toUInt("chanid");
1171  QDateTime starttime = cmdline.toDateTime("starttime");
1172 
1173  if (cmdline.toBool("clearskiplist"))
1174  return ClearSkipList(chanid, starttime);
1175  if (cmdline.toBool("gencutlist"))
1176  return CopySkipListToCutList(chanid, starttime);
1177  if (cmdline.toBool("clearcutlist"))
1178  return SetCutList(chanid, starttime, "");
1179  if (cmdline.toBool("setcutlist"))
1180  return SetCutList(chanid, starttime, cmdline.toString("setcutlist"));
1181  if (cmdline.toBool("getcutlist"))
1182  return GetMarkupList("cutlist", chanid, starttime);
1183  if (cmdline.toBool("getskiplist"))
1184  return GetMarkupList("commflag", chanid, starttime);
1185 
1186  // TODO: check for matching jobid
1187  // create temporary id to operate off of if not
1188 
1189  if (cmdline.toBool("queue"))
1190  QueueCommFlagJob(chanid, starttime, cmdline.toBool("rebuild"));
1191  else if (cmdline.toBool("rebuild"))
1192  result = RebuildSeekTable(chanid, starttime, -1);
1193  else
1194  result = FlagCommercials(chanid, starttime, -1,
1195  cmdline.toString("outputfile"), true);
1196  }
1197  else if (cmdline.toBool("jobid"))
1198  {
1199  jobID = cmdline.toInt("jobid");
1200  uint chanid = 0;
1201  QDateTime starttime;
1202 
1203  if (!JobQueue::GetJobInfoFromID(jobID, jobType, chanid, starttime))
1204  {
1205  std::cerr << "mythcommflag: ERROR: Unable to find DB info for "
1206  << "JobQueue ID# " << jobID << std::endl;
1208  }
1209  force = true;
1210  int jobQueueCPU = gCoreContext->GetNumSetting("JobQueueCPU", 0);
1211 
1212  if (jobQueueCPU < 2)
1213  {
1214  myth_nice(17);
1215  myth_ioprio((0 == jobQueueCPU) ? 8 : 7);
1216  }
1217 
1218  progress = false;
1219 
1220  int ret = 0;
1221 
1223  RebuildSeekTable(chanid, starttime, jobID);
1224  else
1225  ret = FlagCommercials(chanid, starttime, jobID, "", jobQueueCPU != 0);
1226 
1227  if (ret > GENERIC_EXIT_NOT_OK)
1228  {
1229  JobQueue::ChangeJobStatus(jobID, JOB_ERRORED,
1230  QCoreApplication::translate("(mythcommflag)",
1231  "Failed with exit status %1",
1232  "Job status").arg(ret));
1233  }
1234  else
1235  {
1236  JobQueue::ChangeJobStatus(jobID, JOB_FINISHED,
1237  QCoreApplication::translate("(mythcommflag)",
1238  "%n commercial break(s)",
1239  "Job status",
1240  ret));
1241  }
1242  }
1243  else if (cmdline.toBool("video"))
1244  {
1245  // build skiplist for video file
1246  return RebuildSeekTable(cmdline.toString("video"), -1);
1247  }
1248  else if (cmdline.toBool("file"))
1249  {
1250  if (cmdline.toBool("skipdb"))
1251  {
1252  if (cmdline.toBool("rebuild"))
1253  {
1254  std::cerr << "The --rebuild parameter builds the seektable for "
1255  "internal MythTV use only. It cannot be used in "
1256  "combination with --skipdb." << std::endl;
1258  }
1259 
1260  if (!cmdline.toBool("outputfile"))
1261  cmdline.SetValue("outputfile", "-");
1262 
1263  // perform commercial flagging on file outside the database
1264  FlagCommercials(cmdline.toString("file"), -1,
1265  cmdline.toString("outputfile"),
1266  !cmdline.toBool("skipdb"),
1267  true);
1268  }
1269  else
1270  {
1271  ProgramInfo pginfo(cmdline.toString("file"));
1272  // pass chanid and starttime
1273  // inefficient, but it lets the other function
1274  // handle sanity checking
1275  if (cmdline.toBool("rebuild"))
1276  {
1277  result = RebuildSeekTable(pginfo.GetChanID(),
1278  pginfo.GetRecordingStartTime(),
1279  -1, cmdline.toBool("writefile"));
1280  }
1281  else
1282  {
1283  result = FlagCommercials(pginfo.GetChanID(),
1284  pginfo.GetRecordingStartTime(),
1285  -1, cmdline.toString("outputfile"),
1286  true);
1287  }
1288  }
1289  }
1290  else if (cmdline.toBool("queue"))
1291  {
1292  // run flagging for all recordings with no skiplist
1293  MSqlQuery query(MSqlQuery::InitCon());
1294  query.prepare("SELECT r.chanid, r.starttime, c.commmethod "
1295  "FROM recorded AS r "
1296  "LEFT JOIN channel AS c ON r.chanid=c.chanid "
1297 // "WHERE startime >= :STARTTIME AND endtime <= :ENDTIME "
1298  "ORDER BY starttime;");
1299  //query.bindValue(":STARTTIME", allStart);
1300  //query.bindValue(":ENDTIME", allEnd);
1301 
1302  if (query.exec() && query.isActive() && query.size() > 0)
1303  {
1304  QDateTime starttime;
1305 
1306  while (query.next())
1307  {
1308  starttime = MythDate::fromString(query.value(1).toString());
1309  uint chanid = query.value(0).toUInt();
1310 
1311  if (!cmdline.toBool("force") && !cmdline.toBool("rebuild"))
1312  {
1313  // recording is already flagged
1314  if (IsMarked(chanid, starttime))
1315  continue;
1316 
1317  // channel is marked as commercial free
1318  if (query.value(2).toInt() == COMM_DETECT_COMMFREE)
1319  continue;
1320 
1321  // recording rule did not enable commflagging
1322 #if 0
1323  RecordingInfo recinfo(chanid, starttime);
1324  if (!(recinfo.GetAutoRunJobs() & JOB_COMMFLAG))
1325  continue;
1326 #endif
1327  }
1328 
1329  QueueCommFlagJob(chanid, starttime, cmdline.toBool("rebuild"));
1330  }
1331  }
1332 
1333  }
1334  else
1335  {
1336  LOG(VB_GENERAL, LOG_ERR,
1337  "No valid combination of command inputs received.");
1338  cmdline.PrintHelp();
1340  }
1341 
1342  return result;
1343 }
1344 
1345 
1346 /* vim: set expandtab tabstop=4 shiftwidth=4: */
CommDetectorFactory.h
JobQueue::GetJobCmd
static enum JobCmds GetJobCmd(int jobID)
Definition: jobqueue.cpp:1457
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:216
COMM_DETECT_2_ALL
@ COMM_DETECT_2_ALL
Definition: programtypes.h:147
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
FlagCommercials
static int FlagCommercials(ProgramInfo *program_info, int jobid, const QString &outputfilename, bool useDB, bool fullSpeed)
Definition: mythcommflag.cpp:730
ProgramInfo::SaveFilesize
virtual void SaveFilesize(uint64_t fsize)
Sets recording file size in database, and sets "filesize" field.
Definition: programinfo.cpp:6314
COMM_DETECT_SCENE
@ COMM_DETECT_SCENE
Definition: programtypes.h:135
init_output_types
static QMap< QString, OutputMethod > * init_output_types()
Definition: mythcommflag.cpp:117
lastCmd
int lastCmd
Definition: mythcommflag.cpp:81
ProgramInfo::MakeUniqueKey
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:339
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1515
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:215
CustomEventRelayer
Definition: CustomEventRelayer.h:14
COMM_FLAG_NOT_FLAGGED
@ COMM_FLAG_NOT_FLAGGED
Definition: programtypes.h:122
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:79
COMM_DETECT_ALL
@ COMM_DETECT_ALL
Definition: programtypes.h:138
ProgramInfo::GetFilesize
virtual uint64_t GetFilesize(void) const
Definition: programinfo.cpp:6345
MARK_COMM_END
@ MARK_COMM_END
Definition: programtypes.h:61
RemoteGetExistingRecorder
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
Definition: tvremoteutil.cpp:312
CommDetectorBase
Abstract base class for all CommDetectors. Please use the CommDetectFactory to make actual instances.
Definition: CommDetectorBase.h:26
JOB_REBUILD
@ JOB_REBUILD
Definition: jobqueue.h:65
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:143
RemoteEncoder::GetRecorderNumber
int GetRecorderNumber(void) const
Definition: remoteencoder.cpp:62
commDetector
CommDetectorBase * commDetector
Definition: mythcommflag.cpp:75
RemoteFile::GetFileSize
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
Definition: remotefile.cpp:1084
SetCutList
static int SetCutList(uint chanid, const QDateTime &starttime, QString newCutList)
Definition: mythcommflag.cpp:232
mythdb.h
CommDetectorBase::breathe
void breathe()
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:513
myth_ioprio
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
Definition: mythmiscutil.cpp:748
main
int main(int argc, char *argv[])
Definition: mythcommflag.cpp:1108
cmdline
MythCommFlagCommandLineParser cmdline
Definition: mythcommflag.cpp:72
MythCoreContext::UnregisterFileForWrite
void UnregisterFileForWrite(const QString &file)
Definition: mythcorecontext.cpp:2110
mythcommflagplayer.h
progress
bool progress
Definition: mythcommflag.cpp:69
mythcommflag_commandlineparser.h
MythCoreContext::ConnectToMasterServer
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
Definition: mythcorecontext.cpp:355
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
outputMethod
OutputMethod outputMethod
Definition: mythcommflag.cpp:112
MARK_CUT_END
@ MARK_CUT_END
Definition: programtypes.h:56
CommDetectorBase::gotNewCommercialBreakList
void gotNewCommercialBreakList()
MythContext
Startup context for MythTV.
Definition: mythcontext.h:43
QueueCommFlagJob
static int QueueCommFlagJob(uint chanid, const QDateTime &starttime, bool rebuild)
Definition: mythcommflag.cpp:133
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:81
MythCoreContext::RegisterFileForWrite
void RegisterFileForWrite(const QString &file, uint64_t size=0LL)
Definition: mythcorecontext.cpp:2092
JOB_PAUSE
@ JOB_PAUSE
Definition: jobqueue.h:54
commDetectorGotNewCommercialBreakList
static void commDetectorGotNewCommercialBreakList(void)
Definition: mythcommflag.cpp:454
COMM_DETECT_BLANK_SCENE
@ COMM_DETECT_BLANK_SCENE
Definition: programtypes.h:137
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
JOB_RESUME
@ JOB_RESUME
Definition: jobqueue.h:55
CommDetectorBase::statusUpdate
void statusUpdate(const QString &a)
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:119
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:77
JobQueue::GetJobInfoFromID
static bool GetJobInfoFromID(int jobID, int &jobType, uint &chanid, QDateTime &recstartts)
Definition: jobqueue.cpp:664
RemoteFile
Definition: remotefile.h:17
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
ProgramInfo::ExtractKey
static bool ExtractKey(const QString &uniquekey, uint &chanid, QDateTime &recstartts)
Extracts chanid and recstartts from a unique key generated by MakeUniqueKey().
Definition: programinfo.cpp:1177
COMM_DETECT_OFF
@ COMM_DETECT_OFF
Definition: programtypes.h:132
ProgramInfo::SaveCommFlagged
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
Definition: programinfo.cpp:3341
quiet
int quiet
Definition: mythcommflag.cpp:68
MythMediaBuffer
Definition: mythmediabuffer.h:50
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:39
CommDetectorBase::go
virtual bool go()=0
DoFlagCommercials
static int DoFlagCommercials(ProgramInfo *program_info, bool showPercentage, bool fullSpeed, int jobid, MythCommFlagPlayer *cfp, SkipType commDetectMethod, const QString &outputfilename, bool useDB)
Definition: mythcommflag.cpp:539
JOB_STOP
@ JOB_STOP
Definition: jobqueue.h:56
PlayerFlags
PlayerFlags
Definition: mythplayer.h:65
build_compdb.file
file
Definition: build_compdb.py:55
skipTypes
QMap< QString, SkipType > * skipTypes
Definition: mythcommflag.cpp:84
kDecodeLowRes
@ kDecodeLowRes
Definition: mythplayer.h:68
force
bool force
Definition: mythcommflag.cpp:70
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:412
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
remoteutil.h
COMM_FLAG_PROCESSING
@ COMM_FLAG_PROCESSING
Definition: programtypes.h:124
jobID
int jobID
Definition: mythcommflag.cpp:80
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
JobQueue::IsJobRunning
static bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: jobqueue.cpp:1085
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:343
RemoteEncoder
Definition: remoteencoder.h:24
ProgramInfo::SaveCommBreakList
void SaveCommBreakList(frm_dir_map_t &frames) const
Definition: programinfo.cpp:3544
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
mythversion.h
CommDetectorBase::recordingFinished
virtual void recordingFinished(long long totalFileSize)
Definition: CommDetectorBase.h:39
COMM_FLAG_DONE
@ COMM_FLAG_DONE
Definition: programtypes.h:123
COMM_DETECT_2_BLANK
@ COMM_DETECT_2_BLANK
Definition: programtypes.h:143
MythCommandLineParser::Parse
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
Definition: mythcommandlineparser.cpp:1553
kOutputMethodFull
@ kOutputMethodFull
Definition: mythcommflag.cpp:110
mythdate.h
recorderNum
int recorderNum
Definition: mythcommflag.cpp:78
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2438
COMM_DETECT_BLANKS
@ COMM_DETECT_BLANKS
Definition: programtypes.h:134
UpdateFileSize
static void UpdateFileSize(ProgramInfo *program_info)
Definition: mythcommflag.cpp:667
programinfo.h
CommDetectorBase::PrintFullMap
virtual void PrintFullMap(std::ostream &out, const frm_dir_map_t *comm_breaks, bool verbose) const =0
COMM_DETECT_COMMFREE
@ COMM_DETECT_COMMFREE
Definition: programtypes.h:130
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
GENERIC_EXIT_NO_MYTHCONTEXT
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:14
watchingRecording
bool watchingRecording
Definition: mythcommflag.cpp:74
commDetectorStatusUpdate
static void commDetectorStatusUpdate(const QString &status)
Definition: mythcommflag.cpp:445
remotefile.h
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:18
JobQueue::ChangeJobComment
static bool ChangeJobComment(int jobID, const QString &comment="")
Definition: jobqueue.cpp:1009
MYTH_APPNAME_MYTHCOMMFLAG
static constexpr const char * MYTH_APPNAME_MYTHCOMMFLAG
Definition: mythcorecontext.h:25
signalhandling.h
DoesFileExist
static bool DoesFileExist(ProgramInfo *program_info)
Definition: mythcommflag.cpp:645
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
CleanupGuard
Definition: cleanupguard.h:6
GetFileSize
static qint64 GetFileSize(ProgramInfo *program_info)
Definition: mythcommflag.cpp:623
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
MSqlQuery::testDBConnection
static bool testDBConnection()
Checks DB connection + login (login info via Mythcontext)
Definition: mythdbcon.cpp:871
IsMarked
static bool IsMarked(uint chanid, const QDateTime &starttime)
Definition: mythcommflag.cpp:675
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:506
init_skip_types
static QMap< QString, SkipType > * init_skip_types()
Definition: mythcommflag.cpp:86
ProgramInfo::QueryCutList
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
Definition: programinfo.cpp:3465
SlotRelayer.h
MythCommandLineParser::PrintVersion
static void PrintVersion(void)
Print application version information.
Definition: mythcommandlineparser.cpp:1381
GENERIC_EXIT_NO_RECORDING_DATA
@ GENERIC_EXIT_NO_RECORDING_DATA
No program/recording data.
Definition: exitcodes.h:30
mythtranslation.h
MythCommFlagPlayer
Definition: mythcommflagplayer.h:25
OutputMethod
OutputMethod
Definition: mythcommflag.cpp:107
recorder
RemoteEncoder * recorder
Definition: mythcommflag.cpp:76
MythCommandLineParser::toUInt
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2250
MythCommandLineParser::PrintHelp
void PrintHelp(void) const
Print command line option help.
Definition: mythcommandlineparser.cpp:1397
jobqueue.h
GENERIC_EXIT_NOT_OK
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:12
kNoITV
@ kNoITV
Definition: mythplayer.h:76
get_filename
static QString get_filename(ProgramInfo *program_info)
Definition: mythcommflag.cpp:125
MYTH_BINARY_VERSION
static constexpr const char * MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
CommDetectorBase::GetCommercialBreakList
virtual void GetCommercialBreakList(frm_dir_map_t &comms)=0
uint
unsigned int uint
Definition: compat.h:79
kDecodeNoDecode
@ kDecodeNoDecode
Definition: mythplayer.h:72
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
CopySkipListToCutList
static int CopySkipListToCutList(uint chanid, const QDateTime &starttime)
Definition: mythcommflag.cpp:182
MythCommandLineParser::ApplySettingsOverride
void ApplySettingsOverride(void)
Apply all overrides to the global context.
Definition: mythcommandlineparser.cpp:2931
GENERIC_EXIT_PERMISSIONS_ERROR
@ GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
Definition: exitcodes.h:20
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:910
cleanup
static QString cleanup(const QString &str)
Definition: remoteencoder.cpp:673
SlotRelayer
Definition: SlotRelayer.h:16
mythmediabuffer.h
tvremoteutil.h
kDecodeSingleThreaded
@ kDecodeSingleThreaded
Definition: mythplayer.h:69
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
streamOutCommercialBreakList
static void streamOutCommercialBreakList(std::ostream &output, const frm_dir_map_t &commercialBreakList)
Definition: mythcommflag.cpp:332
COMM_DETECT_UNINIT
@ COMM_DETECT_UNINIT
Definition: programtypes.h:131
SignalHandler::Init
static void Init(QObject *parent=nullptr)
Definition: signalhandling.cpp:127
SlotRelayer::relay
void relay()
Definition: SlotRelayer.h:26
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:57
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
MythCommFlagCommandLineParser
Definition: mythcommflag_commandlineparser.h:6
kVideoIsNull
@ kVideoIsNull
Definition: mythplayer.h:74
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
RebuildSeekTable
static int RebuildSeekTable(ProgramInfo *pginfo, int jobid, bool writefile=false)
Definition: mythcommflag.cpp:1017
mythmiscutil.h
CommDetectorBase::resume
void resume()
Definition: CommDetectorBase.cpp:13
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2358
global_program_info
ProgramInfo * global_program_info
Definition: mythcommflag.cpp:77
ProgramInfo::QueryLastFrameInPosMap
uint64_t QueryLastFrameInPosMap(void) const
Returns last frame in position map or 0.
Definition: programinfo.cpp:1893
MythCommandLineParser::SetValue
bool SetValue(const QString &key, const QVariant &value)
Set a new stored value for an existing argument definition, or spawn a new definition store value in.
Definition: mythcommandlineparser.cpp:2829
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2201
MARK_UPDATED_CUT
@ MARK_UPDATED_CUT
Definition: programtypes.h:54
cleanupguard.h
CommDetectorBase::stop
void stop()
Definition: CommDetectorBase.cpp:3
ProgramInfo::GetPlaybackURL
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
Definition: programinfo.cpp:2546
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
JobQueue::GetJobFlags
static enum JobFlags GetJobFlags(int jobID)
Definition: jobqueue.cpp:1499
mythcontext.h
commDetectorBreathe
static void commDetectorBreathe()
Definition: mythcommflag.cpp:406
kDecodeNoLoopFilter
@ kDecodeNoLoopFilter
Definition: mythplayer.h:71
ProgramInfo::SaveCutList
void SaveCutList(frm_dir_map_t &delMap, bool isAutoSave=false) const
Definition: programinfo.cpp:3497
kAudioMuted
@ kAudioMuted
Definition: mythplayer.h:75
GetMarkupList
static int GetMarkupList(const QString &list, uint chanid, const QDateTime &starttime)
Definition: mythcommflag.cpp:273
PlayerContext
Definition: playercontext.h:53
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
remoteencoder.h
ClearSkipList
static int ClearSkipList(uint chanid, const QDateTime &starttime)
Definition: mythcommflag.cpp:211
SkipType
SkipType
This is used as a bitmask.
Definition: programtypes.h:129
ProgramInfo::QueryCommBreakList
void QueryCommBreakList(frm_dir_map_t &frames) const
Definition: programinfo.cpp:3551
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:836
ProgramInfo::SaveMarkupFlag
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
Definition: programinfo.cpp:3755
MythPlayer::SaveTotalDuration
void SaveTotalDuration(void)
Definition: mythplayer.cpp:1966
MythCommandLineParser::ConfigureLogging
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
Definition: mythcommandlineparser.cpp:2862
COMM_DETECT_2_SCENE
@ COMM_DETECT_2_SCENE
Definition: programtypes.h:144
myth_nice
bool myth_nice(int val)
Definition: mythmiscutil.cpp:657
outputTypes
QMap< QString, OutputMethod > * outputTypes
Definition: mythcommflag.cpp:115
CommDetectorFactory::makeCommDetector
static CommDetectorBase * makeCommDetector(SkipType commDetectMethod, bool showProgress, bool fullSpeed, MythCommFlagPlayer *player, int chanid, const QDateTime &startedAt, const QDateTime &stopsAt, const QDateTime &recordingStartedAt, const QDateTime &recordingStopsAt, bool useDB)
Definition: CommDetectorFactory.cpp:10
kOutputMethodEssentials
@ kOutputMethodEssentials
Definition: mythcommflag.cpp:109
CommDetectorBase::requestCommBreakMapUpdate
virtual void requestCommBreakMapUpdate(void)
Definition: CommDetectorBase.h:41
kFlaggerInUseID
const QString kFlaggerInUseID
Definition: programtypes.cpp:23
MythTranslation::load
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
Definition: mythtranslation.cpp:37
exitcodes.h
MythCommandLineParser::toInt
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2223
JobQueue::ChangeJobStatus
static bool ChangeJobStatus(int jobID, int newStatus, const QString &comment="")
Definition: jobqueue.cpp:982
CommDetectorBase.h
COMM_DETECT_LOGO
@ COMM_DETECT_LOGO
Definition: programtypes.h:136
build_compdb.filename
filename
Definition: build_compdb.py:21
incomingCustomEvent
static void incomingCustomEvent(QEvent *e)
Definition: mythcommflag.cpp:479
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:16
GENERIC_EXIT_IN_USE
@ GENERIC_EXIT_IN_USE
Recording in use, can't flag.
Definition: exitcodes.h:35
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:60
output
#define output
Definition: synaesthesia.cpp:220
MythCommandLineParser::toDateTime
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2455
CommDetectorBase::pause
void pause()
Definition: CommDetectorBase.cpp:8
COMM_FLAG_COMMFREE
@ COMM_FLAG_COMMFREE
Definition: programtypes.h:125
gContext
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:57
COMM_DETECT_2
@ COMM_DETECT_2
Definition: programtypes.h:141
print_comm_flag_output
static void print_comm_flag_output(const ProgramInfo *program_info, const frm_dir_map_t &commBreakList, uint64_t frame_count, const CommDetectorBase *commDetect, const QString &output_filename)
Definition: mythcommflag.cpp:357
MythContext::Init
bool Init(bool gui=true, bool promptForBackend=false, bool disableAutoDiscovery=false, bool ignoreDB=false)
Definition: mythcontext.cpp:1584
SignalHandler::Done
static void Done(void)
Definition: signalhandling.cpp:134
COMM_DETECT_2_LOGO
@ COMM_DETECT_2_LOGO
Definition: programtypes.h:142
kDecodeFewBlocks
@ kDecodeFewBlocks
Definition: mythplayer.h:70
CustomEventRelayer.h
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:363
COMM_DETECT_BLANK
@ COMM_DETECT_BLANK
Definition: programtypes.h:133
GENERIC_EXIT_DB_ERROR
@ GENERIC_EXIT_DB_ERROR
Database error.
Definition: exitcodes.h:18