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