11 #include <QApplication>
12 #include <QDomDocument>
13 #include <QDomElement>
18 #include <QRegularExpression>
20 #include <QTimerEvent>
23 #include "libmythbase/mythconfig.h"
77 #define DEBUG_CHANNEL_PREFIX 0
78 #define DEBUG_ACTIONS 0
80 #define LOC QString("TV::%1(): ").arg(__func__)
90 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
92 count = query.
value(0).toInt();
94 LOG(VB_RECORD, LOG_INFO,
95 "ConfiguredTunerCards() = " + QString::number(count));
109 static QMutex s_lock;
110 static TV* s_tv =
nullptr;
111 QMutexLocker locker(&s_lock);
123 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Ref count error");
169 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Already have a player");
175 auto flags =
static_cast<PlayerFlags>(playerflags);
208 LOG(VB_GENERAL, LOG_ERR,
LOC +
"StartPlaying() Failed to start player");
213 MaxWait = (MaxWait <= 0ms) ? 20s : MaxWait;
214 #ifdef USING_VALGRIND
215 MaxWait = std::chrono::milliseconds::max();
216 #endif // USING_VALGRIND
225 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
226 QString(
"StartPlaying(): took %1 ms to start player.")
227 .arg(
t.elapsed().count()));
230 LOG(VB_GENERAL, LOG_ERR,
LOC +
"StartPlaying() Failed to start player");
262 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Already have a TV object.");
267 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- begin");
270 bool quitAll =
false;
271 bool showDialogs =
true;
272 bool playCompleted =
false;
274 bool startSysEventSent =
false;
275 bool startLivetvEventSent =
false;
288 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed initializing TV");
310 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"tv->Playback() -- begin");
315 else if (!startSysEventSent)
317 startSysEventSent =
true;
321 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"tv->Playback() -- end");
325 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"tv->LiveTV() -- begin");
326 if (!tv->
LiveTV(showDialogs, Selection))
331 else if (!startSysEventSent)
333 startSysEventSent =
true;
334 startLivetvEventSent =
true;
338 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"tv->LiveTV() -- end");
343 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No tuners configured");
345 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No tuners free for live tv");
356 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Entering main playback loop.");
358 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Exiting main playback loop.");
366 curProgram = nextProgram;
380 quitAll |= !playerError.isEmpty();
383 QCoreApplication::processEvents();
387 playCompleted =
true;
397 if (startSysEventSent)
405 list.push_back(allowrerecord ?
"1" :
"0");
406 MythEvent me(
"LOCAL_PBB_DELETE_RECORDINGS", list);
417 else if (startSysEventSent)
420 if (!playerError.isEmpty())
430 if (startLivetvEventSent)
433 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- end");
435 return playCompleted;
445 if (name ==
"playbackbox")
447 else if (name ==
"viewscheduled")
449 else if (name ==
"programguide")
451 else if (name ==
"programfinder")
453 else if (name ==
"scheduleeditor")
460 "Play Program"),
"P");
462 "Stop Program"),
"");
464 "Toggle recording status of current program"),
"R");
466 "Page the program guide back one day"),
"Home");
468 "Page the program guide forward one day"),
"End");
470 "Page the program guide left"),
",,<");
472 "Page the program guide right"),
">,.");
474 "Toggle the current channel as a favorite"),
"?");
476 "Reverse the channel order in the program guide"),
"");
478 "Show the Program Guide"),
"S");
480 "Show the Program Finder"),
"#");
482 "Show the Channel Search"),
"");
483 REG_KEY(
"TV Frontend",
"NEXTFAV", QT_TRANSLATE_NOOP(
"MythControls",
484 "Cycle through channel groups and all channels in the "
485 "program guide."),
"/");
486 REG_KEY(
"TV Frontend",
"CHANUPDATE", QT_TRANSLATE_NOOP(
"MythControls",
487 "Switch channels without exiting guide in Live TV mode."),
"X");
489 "Volume down"),
"[,{,F10,Volume Down");
491 "Volume up"),
"],},F11,Volume Up");
493 "Mute"),
"|,\\,F9,Volume Mute");
494 REG_KEY(
"TV Frontend",
"CYCLEAUDIOCHAN", QT_TRANSLATE_NOOP(
"MythControls",
495 "Cycle audio channels"),
"");
496 REG_KEY(
"TV Frontend",
"RANKINC", QT_TRANSLATE_NOOP(
"MythControls",
497 "Increase program or channel rank"),
"Right");
498 REG_KEY(
"TV Frontend",
"RANKDEC", QT_TRANSLATE_NOOP(
"MythControls",
499 "Decrease program or channel rank"),
"Left");
500 REG_KEY(
"TV Frontend",
"UPCOMING", QT_TRANSLATE_NOOP(
"MythControls",
501 "List upcoming episodes"),
"O");
503 "List scheduled upcoming episodes"),
"");
505 "List previously recorded episodes"),
"");
506 REG_KEY(
"TV Frontend",
"DETAILS", QT_TRANSLATE_NOOP(
"MythControls",
507 "Show details"),
"U");
508 REG_KEY(
"TV Frontend",
"VIEWINPUT", QT_TRANSLATE_NOOP(
"MythControls",
509 "Switch Recording Input view"),
"C");
510 REG_KEY(
"TV Frontend",
"CUSTOMEDIT", QT_TRANSLATE_NOOP(
"MythControls",
511 "Edit Custom Record Rule"),
"");
512 REG_KEY(
"TV Frontend",
"CHANGERECGROUP", QT_TRANSLATE_NOOP(
"MythControls",
513 "Change Recording Group"),
"");
514 REG_KEY(
"TV Frontend",
"CHANGEGROUPVIEW", QT_TRANSLATE_NOOP(
"MythControls",
515 "Change Group View"),
"");
517 "List recorded episodes"),
"");
537 if (selectKeys !=
"?")
540 togBkmKeys = selectKeys;
542 bkmKeys = selectKeys;
546 "Add Bookmark"), bkmKeys);
548 "Toggle Bookmark"), togBkmKeys);
549 REG_KEY(
"TV Playback",
"BACK", QT_TRANSLATE_NOOP(
"MythControls",
550 "Exit or return to DVD menu"),
"Esc");
552 "Playback Compact Menu"),
"Alt+M");
554 "Clear OSD"),
"Backspace");
556 "Pause"),
"P,Space");
558 "Fast Forward"),
"Right");
562 "Arbitrary Seek"),
"*");
564 "Seek to a position in seconds"),
"");
566 "Channel up"),
"Up");
568 "Channel down"),
"Down");
569 REG_KEY(
"TV Playback",
"NEXTFAV", QT_TRANSLATE_NOOP(
"MythControls",
570 "Switch to the next favorite channel"),
"/");
571 REG_KEY(
"TV Playback",
"PREVCHAN", QT_TRANSLATE_NOOP(
"MythControls",
572 "Switch to the previous channel"),
"H");
574 "Jump ahead"),
"PgDown");
576 "Jump back"),
"PgUp");
577 REG_KEY(
"TV Playback",
"INFOWITHCUTLIST", QT_TRANSLATE_NOOP(
"MythControls",
578 "Info utilizing cutlist"),
"");
580 "Jump to bookmark"),
"K");
581 REG_KEY(
"TV Playback",
"FFWDSTICKY", QT_TRANSLATE_NOOP(
"MythControls",
582 "Fast Forward (Sticky) or Forward one second while paused"),
">,.");
583 REG_KEY(
"TV Playback",
"RWNDSTICKY", QT_TRANSLATE_NOOP(
"MythControls",
584 "Rewind (Sticky) or Rewind one second while paused"),
",,<");
585 REG_KEY(
"TV Playback",
"NEXTSOURCE", QT_TRANSLATE_NOOP(
"MythControls",
586 "Next Video Source"),
"Y");
587 REG_KEY(
"TV Playback",
"PREVSOURCE", QT_TRANSLATE_NOOP(
"MythControls",
588 "Previous Video Source"),
"");
589 REG_KEY(
"TV Playback",
"NEXTINPUT", QT_TRANSLATE_NOOP(
"MythControls",
591 REG_KEY(
"TV Playback",
"NEXTCARD", QT_TRANSLATE_NOOP(
"MythControls",
593 REG_KEY(
"TV Playback",
"SKIPCOMMERCIAL", QT_TRANSLATE_NOOP(
"MythControls",
594 "Skip Commercial"),
"Z,End");
595 REG_KEY(
"TV Playback",
"SKIPCOMMBACK", QT_TRANSLATE_NOOP(
"MythControls",
596 "Skip Commercial (Reverse)"),
"Q,Home");
598 "Jump to the start of the recording."),
"Ctrl+B");
599 REG_KEY(
"TV Playback",
"TOGGLEBROWSE", QT_TRANSLATE_NOOP(
"MythControls",
600 "Toggle channel browse mode"),
"O");
602 "Toggle recording status of current program"),
"R");
604 "Toggle the current channel as a favorite"),
"?");
606 "Volume down"),
"[,{,F10,Volume Down");
608 "Volume up"),
"],},F11,Volume Up");
610 "Mute"),
"|,\\,F9,Volume Mute");
612 "Set the volume"),
"");
613 REG_KEY(
"TV Playback",
"CYCLEAUDIOCHAN", QT_TRANSLATE_NOOP(
"MythControls",
614 "Cycle audio channels"),
"");
616 "Toggle audio upmixer"),
"Ctrl+U");
618 QT_TRANSLATE_NOOP(
"MythControls",
"Move BottomLine off screen"),
"L");
620 QT_TRANSLATE_NOOP(
"MythControls",
"Save manual zoom for BottomLine"),
"");
621 REG_KEY(
"TV Playback",
"TOGGLEASPECT", QT_TRANSLATE_NOOP(
"MythControls",
622 "Toggle the video aspect ratio"),
"Ctrl+W");
623 REG_KEY(
"TV Playback",
"TOGGLEFILL", QT_TRANSLATE_NOOP(
"MythControls",
624 "Next Preconfigured Zoom mode"),
"W");
626 "Toggle any captions"),
"T");
628 "Enable any captions"),
"");
630 "Disable any captions"),
"");
631 REG_KEY(
"TV Playback",
"TOGGLETTC", QT_TRANSLATE_NOOP(
"MythControls",
632 "Toggle Teletext Captions"),
"");
633 REG_KEY(
"TV Playback",
"TOGGLESUBTITLE", QT_TRANSLATE_NOOP(
"MythControls",
634 "Toggle Subtitles"),
"");
635 REG_KEY(
"TV Playback",
"TOGGLECC608", QT_TRANSLATE_NOOP(
"MythControls",
636 "Toggle VBI CC"),
"");
637 REG_KEY(
"TV Playback",
"TOGGLECC708", QT_TRANSLATE_NOOP(
"MythControls",
638 "Toggle ATSC CC"),
"");
639 REG_KEY(
"TV Playback",
"TOGGLETTM", QT_TRANSLATE_NOOP(
"MythControls",
640 "Toggle Teletext Menu"),
"");
642 "Toggle External Subtitles"),
"");
644 "Enable External Subtitles"),
"");
646 "Disable External Subtitles"),
"");
647 REG_KEY(
"TV Playback",
"TOGGLERAWTEXT", QT_TRANSLATE_NOOP(
"MythControls",
648 "Toggle Text Subtitles"),
"");
650 REG_KEY(
"TV Playback",
"SELECTAUDIO_0", QT_TRANSLATE_NOOP(
"MythControls",
651 "Play audio track 1"),
"");
652 REG_KEY(
"TV Playback",
"SELECTAUDIO_1", QT_TRANSLATE_NOOP(
"MythControls",
653 "Play audio track 2"),
"");
654 REG_KEY(
"TV Playback",
"SELECTSUBTITLE_0",QT_TRANSLATE_NOOP(
"MythControls",
655 "Display subtitle 1"),
"");
656 REG_KEY(
"TV Playback",
"SELECTSUBTITLE_1",QT_TRANSLATE_NOOP(
"MythControls",
657 "Display subtitle 2"),
"");
658 REG_KEY(
"TV Playback",
"SELECTRAWTEXT_0",QT_TRANSLATE_NOOP(
"MythControls",
659 "Display Text Subtitle 1"),
"");
660 REG_KEY(
"TV Playback",
"SELECTCC608_0", QT_TRANSLATE_NOOP(
"MythControls",
661 "Display VBI CC1"),
"");
662 REG_KEY(
"TV Playback",
"SELECTCC608_1", QT_TRANSLATE_NOOP(
"MythControls",
663 "Display VBI CC2"),
"");
664 REG_KEY(
"TV Playback",
"SELECTCC608_2", QT_TRANSLATE_NOOP(
"MythControls",
665 "Display VBI CC3"),
"");
666 REG_KEY(
"TV Playback",
"SELECTCC608_3", QT_TRANSLATE_NOOP(
"MythControls",
667 "Display VBI CC4"),
"");
668 REG_KEY(
"TV Playback",
"SELECTCC708_0", QT_TRANSLATE_NOOP(
"MythControls",
669 "Display ATSC CC1"),
"");
670 REG_KEY(
"TV Playback",
"SELECTCC708_1", QT_TRANSLATE_NOOP(
"MythControls",
671 "Display ATSC CC2"),
"");
672 REG_KEY(
"TV Playback",
"SELECTCC708_2", QT_TRANSLATE_NOOP(
"MythControls",
673 "Display ATSC CC3"),
"");
674 REG_KEY(
"TV Playback",
"SELECTCC708_3", QT_TRANSLATE_NOOP(
"MythControls",
675 "Display ATSC CC4"),
"");
677 "Enable Forced Subtitles"),
"");
679 "Disable Forced Subtitles"),
"");
681 REG_KEY(
"TV Playback",
"NEXTAUDIO", QT_TRANSLATE_NOOP(
"MythControls",
682 "Next audio track"),
"+");
683 REG_KEY(
"TV Playback",
"PREVAUDIO", QT_TRANSLATE_NOOP(
"MythControls",
684 "Previous audio track"),
"-");
685 REG_KEY(
"TV Playback",
"NEXTSUBTITLE", QT_TRANSLATE_NOOP(
"MythControls",
686 "Next subtitle track"),
"");
687 REG_KEY(
"TV Playback",
"PREVSUBTITLE", QT_TRANSLATE_NOOP(
"MythControls",
688 "Previous subtitle track"),
"");
689 REG_KEY(
"TV Playback",
"NEXTRAWTEXT", QT_TRANSLATE_NOOP(
"MythControls",
690 "Next Text track"),
"");
691 REG_KEY(
"TV Playback",
"PREVRAWTEXT", QT_TRANSLATE_NOOP(
"MythControls",
692 "Previous Text track"),
"");
693 REG_KEY(
"TV Playback",
"NEXTCC608", QT_TRANSLATE_NOOP(
"MythControls",
694 "Next VBI CC track"),
"");
695 REG_KEY(
"TV Playback",
"PREVCC608", QT_TRANSLATE_NOOP(
"MythControls",
696 "Previous VBI CC track"),
"");
697 REG_KEY(
"TV Playback",
"NEXTCC708", QT_TRANSLATE_NOOP(
"MythControls",
698 "Next ATSC CC track"),
"");
699 REG_KEY(
"TV Playback",
"PREVCC708", QT_TRANSLATE_NOOP(
"MythControls",
700 "Previous ATSC CC track"),
"");
701 REG_KEY(
"TV Playback",
"NEXTCC", QT_TRANSLATE_NOOP(
"MythControls",
702 "Next of any captions"),
"");
704 REG_KEY(
"TV Playback",
"NEXTSCAN", QT_TRANSLATE_NOOP(
"MythControls",
705 "Next video scan overidemode"),
"");
706 REG_KEY(
"TV Playback",
"QUEUETRANSCODE", QT_TRANSLATE_NOOP(
"MythControls",
707 "Queue the current recording for transcoding"),
"X");
708 REG_KEY(
"TV Playback",
"SPEEDINC", QT_TRANSLATE_NOOP(
"MythControls",
709 "Increase the playback speed"),
"U");
710 REG_KEY(
"TV Playback",
"SPEEDDEC", QT_TRANSLATE_NOOP(
"MythControls",
711 "Decrease the playback speed"),
"J");
712 REG_KEY(
"TV Playback",
"ADJUSTSTRETCH", QT_TRANSLATE_NOOP(
"MythControls",
713 "Turn on time stretch control"),
"A");
714 REG_KEY(
"TV Playback",
"STRETCHINC", QT_TRANSLATE_NOOP(
"MythControls",
715 "Increase time stretch speed"),
"");
716 REG_KEY(
"TV Playback",
"STRETCHDEC", QT_TRANSLATE_NOOP(
"MythControls",
717 "Decrease time stretch speed"),
"");
718 REG_KEY(
"TV Playback",
"TOGGLESTRETCH", QT_TRANSLATE_NOOP(
"MythControls",
719 "Toggle time stretch speed"),
"");
721 QT_TRANSLATE_NOOP(
"MythControls",
722 "Turn on audio sync adjustment controls"),
"");
724 QT_TRANSLATE_NOOP(
"MythControls",
725 "Set the audio sync adjustment"),
"");
726 REG_KEY(
"TV Playback",
"TOGGLEPICCONTROLS",
727 QT_TRANSLATE_NOOP(
"MythControls",
"Playback picture adjustments"),
730 QT_TRANSLATE_NOOP(
"MythControls",
"Set the picture brightness"),
"");
732 QT_TRANSLATE_NOOP(
"MythControls",
"Set the picture contrast"),
"");
734 QT_TRANSLATE_NOOP(
"MythControls",
"Set the picture color"),
"");
736 QT_TRANSLATE_NOOP(
"MythControls",
"Set the picture hue"),
"");
738 QT_TRANSLATE_NOOP(
"MythControls",
"Recording picture adjustments "
739 "for this channel"),
"Ctrl+G");
741 QT_TRANSLATE_NOOP(
"MythControls",
"Recording picture adjustments "
742 "for this recorder"),
"G");
743 REG_KEY(
"TV Playback",
"CYCLECOMMSKIPMODE",
744 QT_TRANSLATE_NOOP(
"MythControls",
"Cycle Commercial Skip mode"),
747 "Show the Program Guide"),
"S");
749 "Show the Program Finder"),
"#");
751 "Toggle the Sleep Timer"),
"F8");
755 "Jump to previously played recording"),
"");
757 "Display menu of recorded programs to jump to"),
"");
759 "Display scheduled recording list"),
"");
761 "Display previously recorded episodes"),
"");
763 "Monitor Signal Quality"),
"Alt+F7");
765 QT_TRANSLATE_NOOP(
"MythControls",
"Jump to the DVD Root Menu"),
"");
767 QT_TRANSLATE_NOOP(
"MythControls",
"Jump to the Popup Menu"),
"");
769 QT_TRANSLATE_NOOP(
"MythControls",
"Jump to the DVD Chapter Menu"),
"");
771 QT_TRANSLATE_NOOP(
"MythControls",
"Jump to the DVD Title Menu"),
"");
773 QT_TRANSLATE_NOOP(
"MythControls",
"Exit Show without any prompts"),
776 "Jump to a chapter"),
"");
778 "Switch title"),
"");
780 "Switch angle"),
"");
782 "OSD Navigation"),
"");
784 "Zoom mode - shift up"),
"");
786 "Zoom mode - shift down"),
"");
788 "Zoom mode - shift left"),
"");
790 "Zoom mode - shift right"),
"");
792 QT_TRANSLATE_NOOP(
"MythControls",
793 "Zoom mode - increase aspect ratio"),
"3");
795 QT_TRANSLATE_NOOP(
"MythControls",
796 "Zoom mode - decrease aspect ratio"),
"7");
798 "Zoom mode - zoom in"),
"9");
800 "Zoom mode - zoom out"),
"1");
802 QT_TRANSLATE_NOOP(
"MythControls",
803 "Zoom mode - vertical zoom in"),
"8");
805 QT_TRANSLATE_NOOP(
"MythControls",
806 "Zoom mode - vertical zoom out"),
"2");
808 QT_TRANSLATE_NOOP(
"MythControls",
809 "Zoom mode - horizontal zoom in"),
"6");
811 QT_TRANSLATE_NOOP(
"MythControls",
812 "Zoom mode - horizontal zoom out"),
"4");
814 "Zoom mode - quit and abandon changes"),
"");
816 "Zoom mode - commit changes"),
"");
822 "Menu Green"),
"F3");
824 "Menu Yellow"),
"F4");
836 "Clear editing cut points"),
"C,Q,Home");
838 "Invert Begin/End cut points"),
"I");
842 "Load cuts from detected commercials"),
"Z,End");
844 "Jump to the next cut point"),
"PgDown");
846 "Jump to the previous cut point"),
"PgUp");
848 "Jump back 10x the normal amount"),
",,<");
850 "Jump forward 10x the normal amount"),
">,.");
852 "Cut point editor compact menu"),
"Alt+M");
856 "Next Page"),
"Down");
858 "Previous Page"),
"Up");
860 "Next Subpage"),
"Right");
862 "Previous Subpage"),
"Left");
864 "Toggle Teletext"),
"T");
868 "Menu Green"),
"F3");
870 "Menu Yellow"),
"F4");
874 "Menu White"),
"F6");
876 QT_TRANSLATE_NOOP(
"MythControls",
"Toggle Background"),
"F7");
878 "Reveal hidden Text"),
"F8");
882 QT_TRANSLATE_NOOP(
"MythControls",
"Toggle audio visualisation"),
"");
886 QT_TRANSLATE_NOOP(
"MythControls",
"Toggle OSD playback information"),
"");
890 QT_TRANSLATE_NOOP(
"MythControls",
"Auto 3D"),
"");
892 QT_TRANSLATE_NOOP(
"MythControls",
"Ignore 3D"),
"");
894 QT_TRANSLATE_NOOP(
"MythControls",
"Discard 3D Side by Side"),
"");
896 QT_TRANSLATE_NOOP(
"MythControls",
"Discard 3D Top and Bottom"),
"");
950 { tr(
"Off",
"Sleep timer"), 0min },
951 { tr(
"30m",
"Sleep timer"), 30min },
952 { tr(
"1h",
"Sleep timer"), 60min },
953 { tr(
"1h30m",
"Sleep timer"), 90min },
954 { tr(
"2h",
"Sleep timer"), 120min }
971 m_mainWindow(MainWindow)
974 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Creating TV object");
976 QObject::setObjectName(
"TV");
993 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Finished creating TV object");
998 QMap<QString,QString> kv;
999 kv[
"LiveTVIdleTimeout"] =
"0";
1000 kv[
"BrowseMaxForward"] =
"240";
1001 kv[
"PlaybackExitPrompt"] =
"0";
1002 kv[
"AutomaticSetWatched"] =
"0";
1003 kv[
"EndOfRecordingExitPrompt"] =
"0";
1004 kv[
"JumpToProgramOSD"] =
"1";
1005 kv[
"GuiSizeForTV"] =
"0";
1006 kv[
"UseVideoModes"] =
"0";
1007 kv[
"JobsRunOnRecordHost"] =
"0";
1008 kv[
"ContinueEmbeddedTVPlay"] =
"0";
1009 kv[
"UseFixedWindowSize"] =
"1";
1010 kv[
"RunFrontendInWindow"] =
"0";
1011 kv[
"PersistentBrowseMode"] =
"0";
1012 kv[
"BrowseAllTuners"] =
"0";
1013 kv[
"ChannelOrdering"] =
"channum";
1015 kv[
"CustomFilters"] =
"";
1016 kv[
"ChannelFormat"] =
"<num> <sign>";
1018 kv[
"TryUnflaggedSkip"] =
"0";
1020 kv[
"ChannelGroupDefault"] =
"-1";
1021 kv[
"BrowseChannelGroup"] =
"0";
1022 kv[
"SmartForward"] =
"0";
1023 kv[
"FFRewReposTime"] =
"100";
1024 kv[
"FFRewReverse"] =
"1";
1026 kv[
"BrowseChannelGroup"] =
"0";
1027 kv[
"ChannelGroupDefault"] =
"-1";
1028 kv[
"ChannelGroupRememberLast"] =
"0";
1030 kv[
"VbiFormat"] =
"";
1031 kv[
"DecodeVBIFormat"] =
"";
1034 kv[
"PlaybackScreenPressKeyMap"] =
"P,Up,Z,],Left,Return,Return,Right,A,Down,Q,[";
1035 kv[
"LiveTVScreenPressKeyMap"] =
"P,Up,Z,S,Left,Return,Return,Right,A,Down,Q,F";
1037 constexpr std::array<const int,8> ff_rew_def { 3, 5, 10, 20, 30, 60, 120, 180 };
1038 for (
size_t i = 0; i < ff_rew_def.size(); i++)
1039 kv[QString(
"FFRewSpeed%1").arg(i)] = QString::number(ff_rew_def[i]);
1046 QString db_channel_ordering;
1048 m_dbIdleTimeout = std::chrono::minutes(kv[
"LiveTVIdleTimeout"].toUInt());
1049 auto db_browse_max_forward = std::chrono::minutes(kv[
"BrowseMaxForward"].toUInt());
1060 db_channel_ordering = kv[
"ChannelOrdering"];
1070 QString beVBI = kv[
"VbiFormat"];
1071 QString feVBI = kv[
"DecodeVBIFormat"];
1088 for (
size_t i = 0; i <
sizeof(ff_rew_def)/
sizeof(ff_rew_def[0]); i++)
1089 m_ffRewSpeeds.push_back(kv[QString(
"FFRewSpeed%1").arg(i)].toInt());
1106 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- begin");
1110 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No MythMainWindow");
1131 fullscreen |= (0 == gui_width && 0 == gui_height);
1146 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Created TvPlayWindow.");
1157 QCoreApplication::processEvents();
1182 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- end");
1188 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- begin");
1209 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"-- lock");
1242 lcd->setFunctionLEDs(
FUNC_TV,
false);
1244 lcd->switchToTime();
1252 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- end");
1262 QCoreApplication::processEvents();
1338 .toUTC().toString(
"yyyy-MM-ddThh:mm:ssZ"));
1349 if (!info.
text[
"totalchapters"].isEmpty())
1351 QList<std::chrono::seconds> chapters;
1354 for (std::chrono::seconds chapter : qAsConst(chapters))
1355 var << QVariant((
long long)chapter.count());
1356 status.insert(
"chaptertimes", var);
1363 int currenttrack = -1;
1366 for (
int i = 0; i < list.size(); i++)
1368 if (i == currenttrack)
1369 status.insert(
"currentsubtitletrack", list[i]);
1370 tracks.insert(
"SELECTSUBTITLE_" + QString::number(i), list[i]);
1377 for (
int i = 0; i < list.size(); i++)
1379 if (i == currenttrack)
1380 status.insert(
"currentsubtitletrack", list[i]);
1381 tracks.insert(
"SELECTTTC_" + QString::number(i), list[i]);
1388 for (
int i = 0; i < list.size(); i++)
1390 if (i == currenttrack)
1391 status.insert(
"currentsubtitletrack", list[i]);
1392 tracks.insert(
"SELECTCC708_" + QString::number(i), list[i]);
1399 for (
int i = 0; i < list.size(); i++)
1401 if (i == currenttrack)
1402 status.insert(
"currentsubtitletrack", list[i]);
1403 tracks.insert(
"SELECTCC608_" + QString::number(i), list[i]);
1410 for (
int i = 0; i < list.size(); i++)
1412 if (i == currenttrack)
1413 status.insert(
"currentsubtitletrack", list[i]);
1414 tracks.insert(
"SELECTRAWTEXT_" + QString::number(i), list[i]);
1420 status.insert(
"currentsubtitletrack", tr(
"External Subtitles"));
1424 status.insert(
"totalsubtitletracks", tracks.size());
1425 if (!tracks.isEmpty())
1426 status.insert(
"subtitletracks", tracks);
1431 for (
int i = 0; i < list.size(); i++)
1433 if (i == currenttrack)
1434 status.insert(
"currentaudiotrack", list[i]);
1435 tracks.insert(
"SELECTAUDIO_" + QString::number(i), list[i]);
1438 status.insert(
"totalaudiotracks", tracks.size());
1439 if (!tracks.isEmpty())
1440 status.insert(
"audiotracks", tracks);
1464 for (
auto tit =info.
text.cbegin(); tit != info.
text.cend(); ++tit)
1465 status.insert(tit.key(), tit.value());
1467 QHashIterator<QString,int> vit(info.
values);
1468 while (vit.hasNext())
1471 status.insert(vit.key(), vit.value());
1499 LOG(VB_GENERAL, LOG_INFO, QString(
"Using Idle Timer. %1 minutes")
1521 else if (!Selection.empty())
1523 for (
const auto & ci : Selection)
1525 uint chanid = ci.m_chanId;
1526 QString channum = ci.m_chanNum;
1527 if (!chanid || channum.isEmpty())
1531 if (chanid && !channum.isEmpty() && !cards.isEmpty())
1569 if (!info->GetChanID())
1576 QString key = info->MakeUniqueKey();
1581 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"AskAllowRecording -- " +
1582 QString(
"adding '%1'").arg(info->m_title));
1590 LOG(VB_GENERAL, LOG_INFO,
LOC +
"-- " +
1591 QString(
"removing '%1'").arg(info->GetTitle()));
1595 delete (*it).m_info;
1612 QString single_rec = tr(
"MythTV wants to record \"%1\" on %2 in %d seconds. Do you want to:");
1614 QString record_watch = tr(
"Record and watch while it records");
1615 QString let_record1 = tr(
"Let it record and go back to the Main Menu");
1616 QString let_recordm = tr(
"Let them record and go back to the Main Menu");
1617 QString record_later1 = tr(
"Record it later, I want to watch TV");
1618 QString record_laterm = tr(
"Record them later, I want to watch TV");
1619 QString do_not_record1= tr(
"Don't let it record, I want to watch TV");
1620 QString do_not_recordm= tr(
"Don't let them record, I want to watch TV");
1627 if ((*it).m_expiry <= timeNow)
1630 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"-- " +
1631 QString(
"removing '%1'").arg((*it).m_info->m_title));
1633 delete (*it).m_info;
1641 std::chrono::milliseconds timeuntil = 0ms;
1648 (*it).m_isInSameInputGroup = (*it).m_isConflicting =
true;
1653 bool busy_input_grps_loaded =
false;
1654 std::vector<uint> busy_input_grps;
1661 (*it).m_isInSameInputGroup =
1662 (cardid == (*it).m_info->GetInputID());
1664 if ((*it).m_isInSameInputGroup)
1668 if (!busy_input_grps_loaded)
1671 busy_input_grps_loaded =
true;
1674 std::vector<uint> input_grps =
1677 for (
uint grp : input_grps)
1679 if (
find(busy_input_grps.begin(), busy_input_grps.end(),
1680 grp) != busy_input_grps.end())
1682 (*it).m_isInSameInputGroup =
true;
1692 if (!(*it).m_isInSameInputGroup)
1693 (*it).m_isConflicting =
false;
1694 else if (cardid == (*it).m_info->GetInputID())
1695 (*it).m_isConflicting =
true;
1697 (*it).m_isConflicting =
true;
1699 (busy_input.
m_mplexId == (*it).m_info->QueryMplexID())) ||
1701 (busy_input.
m_chanId == (*it).m_info->GetChanID())))
1702 (*it).m_isConflicting =
false;
1704 (*it).m_isConflicting =
true;
1706 conflict_count += (*it).m_isConflicting ? 1 : 0;
1713 if (conflict_count == 0)
1715 LOG(VB_GENERAL, LOG_INFO,
LOC +
"The scheduler wants to make "
1716 "a non-conflicting recording.");
1720 else if (conflict_count == 1 && ((*it).m_info->GetInputID() == cardid))
1723 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"UpdateOSDAskAllowDialog -- " +
1731 .replace(
"<num>", (*it).m_info->GetChanNum())
1732 .replace(
"<sign>", (*it).m_info->GetChannelSchedulingID())
1733 .replace(
"<name>", (*it).m_info->GetChannelName());
1735 message = single_rec.arg((*it).m_info->GetTitle(), channel);
1740 dialog.m_buttons.push_back({ record_watch,
"DIALOG_ASKALLOW_WATCH_0",
false, !((*it).m_hasRec)} );
1741 dialog.m_buttons.push_back({ let_record1,
"DIALOG_ASKALLOW_EXIT_0" });
1742 dialog.m_buttons.push_back({ ((*it).m_hasLater) ? record_later1 : do_not_record1,
1743 "DIALOG_ASKALLOW_CANCELRECORDING_0",
false, ((*it).m_hasRec) });
1748 if (conflict_count > 1)
1751 "MythTV wants to record these programs in %d seconds:");
1755 bool has_rec =
false;
1758 if (!(*it).m_isConflicting)
1761 QString title = (*it).m_info->GetTitle();
1762 if ((title.length() < 10) && !(*it).m_info->GetSubtitle().isEmpty())
1763 title +=
": " + (*it).m_info->GetSubtitle();
1764 if (title.length() > 20)
1765 title = title.left(17) +
"...";
1769 .replace(
"<num>", (*it).m_info->GetChanNum())
1770 .replace(
"<sign>", (*it).m_info->GetChannelSchedulingID())
1771 .replace(
"<name>", (*it).m_info->GetChannelName());
1773 if (conflict_count > 1)
1775 message += tr(
"\"%1\" on %2").arg(title, channel);
1780 message = single_rec.arg((*it).m_info->GetTitle(), channel);
1781 has_rec = (*it).m_hasRec;
1785 if (conflict_count > 1)
1788 message += tr(
"Do you want to:");
1791 bool all_have_later =
true;
1792 timeuntil = 9999999ms;
1795 if ((*it).m_isConflicting)
1797 all_have_later &= (*it).m_hasLater;
1799 timeuntil = std::clamp(
tmp, 0ms, timeuntil);
1802 timeuntil = (9999999ms == timeuntil) ? 0ms : timeuntil;
1804 if (conflict_count > 1)
1808 { let_recordm,
"DIALOG_ASKALLOW_EXIT_0",
false,
true },
1809 { all_have_later ? record_laterm : do_not_recordm,
"DIALOG_ASKALLOW_CANCELCONFLICTING_0" }
1816 { let_record1,
"DIALOG_ASKALLOW_EXIT_0",
false, !has_rec},
1817 { all_have_later ? record_later1 : do_not_record1,
"DIALOG_ASKALLOW_CANCELRECORDING_0",
false, has_rec}
1830 LOG(VB_GENERAL, LOG_ERR,
"allowrecordingbox : askAllowLock is locked");
1834 if (
Action ==
"CANCELRECORDING")
1839 else if (
Action ==
"CANCELCONFLICTING")
1843 if (pgm.m_isConflicting)
1847 else if (
Action ==
"WATCH")
1911 #define TRANSITION(ASTATE,BSTATE) ((ctxState == (ASTATE)) && (desiredNextState == (BSTATE)))
1913 #define SET_NEXT() do { nextState = desiredNextState; changed = true; } while(false)
1914 #define SET_LAST() do { nextState = ctxState; changed = true; } while(false)
1919 QByteArray msg_arr = msg.toLatin1();
1920 QString msg_i18n = TV::tr(msg_arr.constData());
1921 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
1922 return (msg_arr == msg_i18n_arr) ? msg_i18n : msg;
1937 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Called after fatal error detected.");
1941 bool changed =
false;
1947 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Warning, called with no state to change to.");
1955 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Attempting to change from %1 to %2")
1960 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Attempting to set to an error state!");
1985 QString channum =
"";
1989 QStringList reclist;
1992 query.
prepare(
"SELECT channum FROM channel "
1993 "WHERE chanid = :CHANID");
1996 channum = query.
value(0).toString();
1998 channum = QString::number(chanid);
2001 QString::number(chanid));
2006 if (!reclist.empty())
2021 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Spawning LiveTV Recorder -- begin");
2023 if (chanid && !channum.isEmpty())
2028 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Spawning LiveTV Recorder -- end");
2032 LOG(VB_GENERAL, LOG_ERR,
LOC +
"LiveTV not successfully started");
2046 LOG(VB_GENERAL, LOG_INFO,
LOC +
2047 QString(
"playbackURL(%1) inputtype(%2)")
2052 playbackURL,
false,
true,
2066 LOG(VB_GENERAL, LOG_ERR,
LOC +
"LiveTV not successfully started");
2120 LOG(VB_GENERAL, LOG_ERR,
LOC +
2121 "Couldn't find recorder for in-progress recording");
2140 QString message =
"COMMFLAG_REQUEST ";
2155 TV::tr(
"TV Player" ),
2182 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown state transition: %1 to %2")
2187 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Changing from %1 to %2")
2198 LOG(VB_GENERAL, LOG_INFO,
LOC +
"State is LiveTV");
2200 LOG(VB_GENERAL, LOG_INFO,
LOC +
"UpdateOSDInput done");
2202 LOG(VB_GENERAL, LOG_INFO,
LOC +
"UpdateLCD done");
2204 LOG(VB_GENERAL, LOG_INFO,
LOC +
"ITVRestart done");
2210 QString msg = tr(
"%1 Settings")
2263 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Main UI disabled.");
2266 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
" -- end");
2281 MaxWait = (MaxWait <= 0ms) ? 40s : MaxWait;
2284 bool recording =
false;
2288 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid Remote Encoder");
2296 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Lost contact with backend");
2300 std::this_thread::sleep_for(5us);
2306 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Timed out waiting for recorder to start");
2310 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Took %1 ms to start recorder.")
2311 .arg(
t.elapsed().count()));
2330 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- begin");
2344 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Stopping ring buffer");
2355 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"stopping recorder");
2360 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"-- end");
2365 const int timer_id =
Event->timerId();
2373 bool handled =
true;
2434 if (!netCmd.isEmpty())
2459 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Last Program File does not exist");
2576 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Unknown timer: %1").arg(timer_id));
2586 QString lcd_time_string;
2587 bool showProgress =
true;
2604 lcd_time_string = info.
text[
"playedtime"] +
" / " + info.
text[
"totaltime"];
2606 if (lcd_time_string.length() >
static_cast<int>(lcd->
getLCDWidth()))
2607 lcd_time_string.remove(
' ');
2637 int timer = startTimer(Interval);
2639 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to start timer on line %1 of %2").arg(Line).arg(__FILE__));
2656 auto StateChange = [&]()
2674 QTimer::singleShot(0,
this, StateChange);
2679 auto InputChange = [&]()
2691 QTimer::singleShot(0,
this, InputChange);
2703 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switching to program: %1")
2762 bool is_playing =
false;
2847 bool restartTimer =
false;
2853 restartTimer =
true;
2857 LOG(VB_CHANNEL, LOG_INFO,
"REC_PROGRAM -- channel change");
2923 if ((
Event->type() == QEvent::Resize))
2929 if ( (QEvent::KeyPress ==
Event->type() || QEvent::KeyRelease ==
Event->type())
2931 return TVPlaybackState::eventFilter(Object,
Event);
2933 QScopedPointer<QEvent> sNewEvent(
nullptr);
2937 if (QEvent::KeyPress ==
Event->type())
2952 switch (
Event->type())
2955 case QEvent::UpdateRequest:
2959 return TVPlaybackState::eventFilter(Object,
Event);
2962 return TVPlaybackState::eventFilter(Object,
Event);
2969 if (
Event ==
nullptr)
2970 return TVPlaybackState::event(
Event);
2972 if (QEvent::Resize ==
Event->type())
2977 const auto *qre =
dynamic_cast<const QResizeEvent*
>(
Event);
2980 return TVPlaybackState::event(
Event);
2989 if (QEvent::KeyPress ==
Event->type())
2991 const auto * ke =
dynamic_cast<QKeyEvent*
>(
Event);
2994 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"keypress: %1 '%2'")
2995 .arg(ke->key()).arg(ke->text()));
3003 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"mythgesture: g:%1 pos:%2,%3 b:%4")
3004 .arg(ge->GetGesture()).arg(ge->GetPosition().x())
3005 .arg(ge->GetPosition().y()).arg(ge->GetButton()));
3009 bool handled =
false;
3018 switch (
Event->type())
3021 case QEvent::UpdateRequest:
3031 return QObject::event(
Event);
3036 bool handled =
true;
3091 else if (
Action.startsWith(
"TOGGLE"))
3101 else if (
Action.startsWith(
"SELECT"))
3110 else if (
Action.startsWith(
"NEXT") ||
Action.startsWith(
"PREV"))
3112 int dir = (
Action.startsWith(
"NEXT")) ? +1 : -1;
3116 else if (
Action.endsWith(
"CC"))
3139 QStringList::const_iterator it;
3140 for (it = actions.begin(); it != actions.end(); ++it)
3142 if ((*it).startsWith(
"SYSEVENT") ||
3155 QList<QKeyEvent*> keyPressList;
3157 QStringList stringKeyList = KeyList.split(
',');
3158 for (
const auto & str : qAsConst(stringKeyList))
3160 QKeySequence keySequence(str);
3161 for (i = 0; i < keySequence.count(); i++)
3163 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
3164 int keynum = keySequence[i];
3165 int keyCode = keynum & ~Qt::KeyboardModifierMask;
3166 auto modifiers =
static_cast<Qt::KeyboardModifiers
>(keynum & Qt::KeyboardModifierMask);
3168 int keyCode = keySequence[i].key();
3169 Qt::KeyboardModifiers modifiers = keySequence[i].keyboardModifiers();
3171 auto * keyEvent =
new QKeyEvent(QEvent::None, keyCode, modifiers);
3172 keyPressList.append(keyEvent);
3180 auto * keyEvent =
new QKeyEvent(QEvent::None, Qt::Key_Escape, Qt::NoModifier);
3181 keyPressList.append(keyEvent);
3184 return keyPressList;
3188 QStringList &Actions,
bool IsLiveTV)
3190 if (
Event && Context ==
"TV Playback")
3197 (
Event->GetButton() == Qt::LeftButton))
3201 QPoint pos =
Event->GetPosition();
3203 const int widthDivider = 4;
3204 int w4 = size.width() / widthDivider;
3205 region = pos.x() / w4;
3206 int h3 = size.height() / 3;
3207 region += (pos.y() / h3) * widthDivider;
3219 QStringList &Actions,
bool IsLiveTV,
bool AllowJumps)
3223 if (QEvent::KeyPress ==
Event->type())
3233 if (
Event ==
nullptr)
3239 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"ignoreKeys: %1").arg(ignoreKeys));
3250 auto* eKeyEvent =
dynamic_cast<QKeyEvent*
>(
Event);
3252 if (eKeyEvent->key() <= 0)
3255 switch(eKeyEvent->nativeScanCode())
3258 keycode = Qt::Key_MediaPause;
3266 auto *key =
new QKeyEvent(QEvent::KeyPress, keycode, eKeyEvent->modifiers());
3267 QCoreApplication::postEvent(
this, key);
3273 QStringList actions;
3274 bool handled =
false;
3275 bool alreadyTranslatedPlayback =
false;
3283 alreadyTranslatedPlayback =
true;
3285 if (handled || actions.isEmpty())
3288 bool esc =
IsActionable({
"ESCAPE",
"BACK" }, actions);
3299 if (QEvent::KeyPress ==
Event->type())
3301 auto *qke =
dynamic_cast<QKeyEvent*
>(
Event);
3359 if (QEvent::KeyPress ==
Event->type())
3361 auto *qke =
dynamic_cast<QKeyEvent*
>(
Event);
3364 const QString txt = qke->text();
3368 (void)txt.toInt(&ok, 16);
3369 if (ok || txt==
"_" || txt==
"-" || txt==
"#" || txt==
".")
3380 QStringList tt_actions;
3383 if (!handled && !tt_actions.isEmpty())
3385 for (
const QString&
action : qAsConst(tt_actions))
3397 if (!alreadyTranslatedPlayback)
3400 alreadyTranslatedPlayback =
true;
3403 if (!handled && !actions.isEmpty())
3405 for (
const QString&
action : qAsConst(actions))
3414 if (!alreadyTranslatedPlayback)
3417 if (handled || actions.isEmpty())
3425 if (QEvent::KeyPress ==
Event->type())
3441 for (
int i = 0; i < actions.size(); ++i)
3442 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"handled(%1) actions[%2](%3)")
3443 .arg(handled).arg(i).arg(actions[i]));
3444 #endif // DEBUG_ACTIONS
3451 for (
int i = 0; i < actions.size() && !handled; i++)
3453 QString
action = actions[i];
3455 int val =
action.toInt(&ok);
3473 bool handled =
true;
3494 for (
const auto&
action : qAsConst(Actions))
3505 static const QStringList passthrough =
3508 ACTION_MUTEAUDIO,
"CYCLEAUDIOCHAN",
"BOTTOMLINEMOVE",
"BOTTOMLINESAVE",
"TOGGLEASPECT"
3518 bool endmanualzoom =
false;
3519 bool handled =
true;
3520 bool updateOSD =
true;
3549 endmanualzoom =
true;
3553 endmanualzoom =
true;
3560 static const QStringList passthrough =
3568 QString msg = tr(
"Zoom Committed");
3572 msg = endmanualzoom ? tr(
"Zoom Ignored") :
3577 else if (endmanualzoom)
3624 bool handled =
true;
3649 bool handled =
true;
3672 bool handled =
true;
3695 bool handled =
true;
3730 bool IsDVD,
bool IsDVDStillFrame)
3732 bool handled =
true;
3736 else if (
IsActionable(
"SKIPCOMMBACK", Actions) && !IsDVD)
3738 else if (
IsActionable(
"QUEUETRANSCODE", Actions) && !IsDVD)
3740 else if (
IsActionable(
"QUEUETRANSCODE_AUTO", Actions) && !IsDVD)
3742 else if (
IsActionable(
"QUEUETRANSCODE_HIGH", Actions) && !IsDVD)
3744 else if (
IsActionable(
"QUEUETRANSCODE_MEDIUM", Actions) && !IsDVD)
3746 else if (
IsActionable(
"QUEUETRANSCODE_LOW", Actions) && !IsDVD)
3752 else if (
IsActionable(
"SPEEDINC", Actions) && !IsDVDStillFrame)
3754 else if (
IsActionable(
"SPEEDDEC", Actions) && !IsDVDStillFrame)
3758 else if (
IsActionable(
"CYCLECOMMSKIPMODE",Actions) && !IsDVD)
3814 DoSeek(0, tr(
"Jump to Beginning"),
false,
true);
3838 std::chrono::milliseconds rate =
m_sigMonMode ? 0ms : 100ms;
3873 bool visible =
false;
3943 else if (
IsActionable({
"INFO",
"INFOWITHCUTLIST" }, Actions))
3962 for (
auto it = Actions.cbegin(); it != Actions.cend() && !handled; ++it)
3971 bool handled =
false;
3975 for (
int i = 0; i < Actions.size() && !handled; i++)
3977 const QString&
action = Actions[i];
3979 int val =
action.toInt(&ok);
4008 bool handled =
true;
4087 info.
text[
"title"] = tr(
"Position");
4095 bool handled =
true;
4115 else if (
IsActionable(
"NEXTSOURCE", Actions) && islivetv)
4117 else if (
IsActionable(
"PREVSOURCE", Actions) && islivetv)
4119 else if (
IsActionable(
"NEXTINPUT", Actions) && islivetv)
4123 else if (
IsActionable(
"PREVCHAN", Actions) && islivetv)
4177 #ifdef DEBUG_ACTIONS
4178 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"(%1) ignoreKeys: %2").arg(
Command).arg(ignoreKeys));
4183 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Ignoring network control command because ignoreKeys is set");
4187 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
4188 QStringList tokens =
Command.split(
" ", QString::SkipEmptyParts);
4190 QStringList tokens =
Command.split(
" ", Qt::SkipEmptyParts);
4192 if (tokens.size() < 2)
4194 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Not enough tokens in network control command " + QString(
"'%1'").arg(
Command));
4206 LOG(VB_GENERAL, LOG_WARNING,
LOC +
4207 "Ignoring network control command\n\t\t\t" +
4208 QString(
"because dialog is waiting for a response"));
4212 if (tokens[1] !=
"QUERY")
4215 if (tokens.size() == 3 && tokens[1] ==
"CHANID")
4221 else if (tokens.size() == 3 && tokens[1] ==
"CHANNEL")
4225 static const QRegularExpression kChannelNumRE { R
"(^[-\.\d_#]+$)" };
4226 if (tokens[2] ==
"UP")
4228 else if (tokens[2] ==
"DOWN")
4230 else if (tokens[2].contains(kChannelNumRE))
4234 else if (tokens.size() == 3 && tokens[1] ==
"SPEED")
4238 if (tokens[2] ==
"0x")
4245 else if (tokens[2] ==
"normal")
4255 static const QRegularExpression kSpeedRE { R
"(^\-*(\d*\.)?\d+x$)" };
4256 float tmpSpeed = 1.0F;
4259 if (tokens[2].contains(kSpeedRE))
4261 QString speed = tokens[2].left(tokens[2].length()-1);
4262 tmpSpeed = speed.toFloat(&ok);
4266 static const QRegularExpression re { R
"(^(\-*\d+)\/(\d+)x$)" };
4267 auto match = re.match(tokens[2]);
4268 if (match.hasMatch())
4270 QStringList matches = match.capturedTexts();
4271 int numerator = matches[1].toInt(&ok);
4272 int denominator = matches[2].toInt(&ok);
4274 if (ok && denominator != 0)
4275 tmpSpeed =
static_cast<float>(numerator) /
static_cast<float>(denominator);
4283 float searchSpeed = fabs(tmpSpeed);
4288 if (tmpSpeed == 0.0F)
4296 else if (tmpSpeed == 1.0F)
4315 else if (tmpSpeed > 1)
4323 else if (0.125F <= tmpSpeed && tmpSpeed <= 2.0F)
4331 LOG(VB_GENERAL, LOG_WARNING, QString(
"Couldn't find %1 speed. Setting Speed to 1x")
4332 .arg(
static_cast<double>(searchSpeed)));
4339 LOG(VB_GENERAL, LOG_ERR, QString(
"Found an unknown speed of %1").arg(tokens[2]));
4343 else if (tokens.size() == 2 && tokens[1] ==
"STOP")
4350 static const QRegularExpression kDigitsRE {
"^\\d+$" };
4354 if (tokens[2] ==
"BEGINNING")
4356 DoSeek(0, tr(
"Jump to Beginning"),
false,
true);
4358 else if (tokens[2] ==
"FORWARD")
4362 else if (tokens[2] ==
"BACKWARD")
4366 else if ((tokens[2] ==
"POSITION" ||
4367 tokens[2] ==
"POSITIONWITHCUTLIST") &&
4368 (tokens.size() == 4) &&
4369 (tokens[3].contains(kDigitsRE)))
4371 DoSeekAbsolute(tokens[3].toInt(), tokens[2] ==
"POSITIONWITHCUTLIST");
4374 else if (tokens.size() >= 3 && tokens[1] ==
"SUBTITLES")
4377 uint track = tokens[2].toUInt(&ok);
4389 uint size =
static_cast<uint>(subs.size());
4392 if (track >=
start && track < finish)
4401 finish =
start + size;
4402 if (track >=
start && track < finish)
4411 finish =
start + size;
4412 if (track >=
start && track < finish)
4421 finish =
start + size;
4422 if (track >=
start && track < finish)
4431 finish =
start + size;
4432 if (track >=
start && track < finish)
4441 finish =
start + size;
4442 if (track >=
start && track < finish)
4450 else if (tokens.size() >= 3 && tokens[1] ==
"VOLUME")
4452 static const QRegularExpression re {
"(\\d+)%?" };
4453 auto match = re.match(tokens[2]);
4454 if (match.hasMatch())
4456 QStringList matches = match.capturedTexts();
4458 LOG(VB_GENERAL, LOG_INFO, QString(
"Set Volume to %1%").arg(matches[1]));
4461 int vol = matches[1].toInt(&ok);
4465 if (0 <= vol && vol <= 100)
4469 else if (tokens.size() >= 3 && tokens[1] ==
"QUERY")
4471 if (tokens[2] ==
"POSITION")
4486 static const QRegularExpression re {
"Play (.*)x" };
4488 if (match.hasMatch())
4490 QStringList matches = match.capturedTexts();
4491 speedStr = QString(
"%1x").arg(matches[1]);
4503 QString infoStr =
"";
4527 infoStr =
"Recorded";
4535 QString bufferFilename =
4537 if ((infoStr ==
"Recorded") || (infoStr ==
"LiveTV"))
4539 infoStr += QString(
" %1 %2 %3 %4 %5 %6 %7")
4540 .arg(info.
text[
"description"],
4545 QString::number(fplay),
4547 QString::number(rate));
4551 QString position = info.
text[
"description"].section(
" ",0,0);
4552 infoStr += QString(
" %1 %2 %3 %4 %5")
4556 QString::number(fplay),
4557 QString::number(rate));
4560 infoStr += QString(
" Subtitles:");
4565 infoStr += QString(
" *0:[None]*");
4567 infoStr += QString(
" 0:[None]");
4572 for (
int i = 0; i < subs.size(); i++)
4575 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4577 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4582 for (
int i = 0; i < subs.size(); i++)
4585 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4587 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4592 for (
int i = 0; i < subs.size(); i++)
4595 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4597 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4602 for (
int i = 0; i < subs.size(); i++)
4605 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4607 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4612 for (
int i = 0; i < subs.size(); i++)
4615 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4617 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4622 for (
int i = 0; i < subs.size(); i++)
4625 infoStr += QString(
" *%1:[%2]*").arg(n).arg(subs[i]);
4627 infoStr += QString(
" %1:[%2]").arg(n).arg(subs[i]);
4633 QString message = QString(
"NETWORK_CONTROL ANSWER %1").arg(infoStr);
4637 else if (tokens[2] ==
"VOLUME")
4640 QString message = QString(
"NETWORK_CONTROL ANSWER %1").arg(infoStr);
4649 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"(%1) -- begin").arg(
StateToString(desiredState)));
4656 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Created player."));
4661 LOG(VB_GENERAL, LOG_CRIT,
LOC + QString(
"Failed to create player."));
4664 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"(%1) -- end %2")
4770 bool paused =
false;
4792 bool ignore =
false;
4793 bool paused =
false;
4818 if (Time > -0.001F && Time < +0.001F)
4821 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"%1 seconds").arg(
static_cast<double>(Time)));
4842 else if (Time < 0.0F)
4854 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"%1").arg(FrameNum));
4880 const int kRewind = 4;
4881 const int kForward = 8;
4882 const int kSticky = 16;
4883 const int kSlippery = 32;
4884 const int kRelative = 64;
4885 const int kAbsolute = 128;
4886 const int kIgnoreCutlist = 256;
4887 const int kWhenceMask = 3;
4892 flags =
ARBSEEK_END | kForward | kSticky | kAbsolute;
4898 flags =
ARBSEEK_SET | kRewind | kSticky | kAbsolute;
4904 int direction = (flags & kRewind) ? -1 : 1;
4913 QString message = (flags & kRewind) ? tr(
"Rewind") :
4915 if (flags & kAbsolute)
4917 float time = direction;
4918 DoSeek(time, message,
true, (flags & kIgnoreCutlist) == 0);
4925 uint64_t targetRel = frameRel +
static_cast<uint64_t
>(direction);
4926 if (frameRel == 0 && direction < 0)
4930 if (targetRel > maxRel)
4939 else if (flags & kSticky)
4943 else if (flags & kRewind)
4963 void TV::DoSeek(
float Time,
const QString &Msg,
bool TimeIsOffset,
bool HonorCutlist)
4968 bool limitkeys =
false;
5008 DoSeek(Seconds, tr(
"Jump To"),
false, HonorCutlist);
5020 int64_t time = (int(seek / 100) * 3600) + ((seek % 100) * 60);
5024 DoSeek(time, tr(
"Jump Ahead"),
true, HonorCutlist);
5028 DoSeek(-time, tr(
"Jump Back"),
true, HonorCutlist);
5041 DoSeek(std::max(0.0F, dur -
static_cast<float>(time)), tr(
"Jump To"),
false, HonorCutlist);
5175 auto index =
static_cast<size_t>(Index);