MythTV  master
mythtv/programs/mythavtest/main.cpp
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <iostream>
3 #include <utility>
4 
5 using namespace std;
6 
7 #include <QApplication>
8 #include <QDir>
9 #include <QRegExp>
10 #include <QString>
11 #include <QSurfaceFormat>
12 #include <QTime>
13 
14 #include "tv_play.h"
15 #include "programinfo.h"
16 #include "commandlineparser.h"
17 #include "mythplayer.h"
18 #include "jitterometer.h"
19 
20 #include "exitcodes.h"
21 #include "mythcontext.h"
22 #include "mythversion.h"
23 #include "mythdbcon.h"
24 #include "compat.h"
25 #include "dbcheck.h"
26 #include "mythlogging.h"
27 #include "signalhandling.h"
28 #include "mythmiscutil.h"
29 #include "mythvideoout.h"
30 
31 // libmythui
32 #include "mythuihelper.h"
33 #include "mythmainwindow.h"
34 
36 {
37  public:
38  VideoPerformanceTest(QString filename, bool decodeno, bool onlydecode,
39  int runfor, bool deint, bool gpu)
40  : m_file(std::move(filename)),
41  m_noDecode(decodeno),
42  m_decodeOnly(onlydecode),
43  m_secondsToRun(runfor),
44  m_deinterlace(deint),
45  m_allowGpu(gpu),
46  m_ctx(nullptr)
47  {
48  if (m_secondsToRun < 1)
49  m_secondsToRun = 1;
50  if (m_secondsToRun > 3600)
51  m_secondsToRun = 3600;
52  }
53 
55  {
56  delete m_ctx;
57  }
58 
59  void Test(void)
60  {
61  PIPMap dummy;
62  MythMediaBuffer *rb = MythMediaBuffer::Create(m_file, false, true, 2000);
63  auto *mp = new MythPlayer(
65  mp->GetAudio()->SetAudioInfo("NULL", "NULL", 0, 0);
66  mp->GetAudio()->SetNoAudio();
67  m_ctx = new PlayerContext("VideoPerformanceTest");
68  m_ctx->SetRingBuffer(rb);
69  m_ctx->SetPlayer(mp);
70  auto *pinfo = new ProgramInfo(m_file);
71  m_ctx->SetPlayingInfo(pinfo); // makes a copy
72  delete pinfo;
73  mp->SetPlayerInfo(nullptr, GetMythMainWindow(), m_ctx);
74 
76  if (!mp->StartPlaying())
77  {
78  LOG(VB_GENERAL, LOG_ERR, "Failed to start playback.");
79  return;
80  }
81 
82  MythVideoOutput *vo = mp->GetVideoOutput();
83  if (!vo)
84  {
85  LOG(VB_GENERAL, LOG_ERR, "No video output.");
86  return;
87  }
88 
89  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
90  LOG(VB_GENERAL, LOG_INFO, "Ensure Sync to VBlank is disabled.");
91  LOG(VB_GENERAL, LOG_INFO, "Otherwise rate will be limited to that of the display.");
92  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
93  LOG(VB_GENERAL, LOG_INFO, QString("Starting video performance test for '%1'.")
94  .arg(m_file));
95  LOG(VB_GENERAL, LOG_INFO, QString("Test will run for %1 seconds.")
96  .arg(m_secondsToRun));
97 
98  if (m_noDecode)
99  LOG(VB_GENERAL, LOG_INFO, "No decode after startup - checking display performance");
100  else if (m_decodeOnly)
101  LOG(VB_GENERAL, LOG_INFO, "Decoding frames only - skipping display.");
102  DecoderBase* dec = mp->GetDecoder();
103  if (dec)
104  LOG(VB_GENERAL, LOG_INFO, QString("Using decoder: %1").arg(dec->GetCodecDecoderName()));
105 
106  auto *jitter = new Jitterometer("Performance: ", static_cast<int>(mp->GetFrameRate()));
107 
108  int ms = m_secondsToRun * 1000;
109  QTime start = QTime::currentTime();
110  VideoFrame *frame = nullptr;
111  while (true)
112  {
113  mp->ProcessCallbacks();
114  int duration = start.msecsTo(QTime::currentTime());
115  if (duration < 0 || duration > ms)
116  {
117  LOG(VB_GENERAL, LOG_INFO, "Complete.");
118  break;
119  }
120 
121  if (mp->IsErrored())
122  {
123  LOG(VB_GENERAL, LOG_ERR, "Playback error.");
124  break;
125  }
126 
127  if (mp->GetEof() != kEofStateNone)
128  {
129  LOG(VB_GENERAL, LOG_INFO, "End of file.");
130  break;
131  }
132 
133  if (!mp->PrebufferEnoughFrames())
134  continue;
135 
136  mp->SetBuffering(false);
137  vo->StartDisplayingFrame();
138  if ((m_noDecode && !frame) || !m_noDecode)
139  frame = vo->GetLastShownFrame();
140  mp->CheckAspectRatio(frame);
141 
142  if (!m_decodeOnly)
143  {
145  vo->ProcessFrame(frame, nullptr, dummy, scan);
146  vo->PrepareFrame(frame, scan, nullptr);
147  vo->Show(scan);
148 
149  if (doubledeint && m_deinterlace)
150  {
151  doubledeint = GetDoubleRateOption(frame, DEINT_CPU);
153  if (doubledeint && !other)
154  vo->ProcessFrame(frame, nullptr, dummy, kScan_Intr2ndField);
155  vo->PrepareFrame(frame, kScan_Intr2ndField, nullptr);
156  vo->Show(scan);
157  }
158  }
159  if (!m_noDecode)
160  vo->DoneDisplayingFrame(frame);
161  jitter->RecordCycleTime();
162  }
163  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
164  delete jitter;
165  }
166 
167  private:
168  QString m_file;
175 };
176 
177 int main(int argc, char *argv[])
178 {
180  if (!cmdline.Parse(argc, argv))
181  {
182  cmdline.PrintHelp();
184  }
185 
186  if (cmdline.toBool("showhelp"))
187  {
188  cmdline.PrintHelp();
189  return GENERIC_EXIT_OK;
190  }
191 
192  if (cmdline.toBool("showversion"))
193  {
195  return GENERIC_EXIT_OK;
196  }
197 
198  int swapinterval = 1;
199  if (cmdline.toBool("test"))
200  {
201  // try and disable sync to vblank on linux x11
202  qputenv("vblank_mode", "0"); // Intel and AMD
203  qputenv("__GL_SYNC_TO_VBLANK", "0"); // NVidia
204  // the default surface format has a swap interval of 1. This is used by
205  // the MythMainwindow widget that then drives vsync for all widgets/children
206  // (i.e. MythPainterWindow) and we cannot override it on some drivers. So
207  // force the default here.
208  swapinterval = 0;
209  }
210 
211  MythDisplay::ConfigureQtGUI(swapinterval);
212 
213  QApplication a(argc, argv);
214  QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHAVTEST);
215 
216  int retval = cmdline.ConfigureLogging();
217  if (retval != GENERIC_EXIT_OK)
218  return retval;
219 
220  if (!cmdline.toString("display").isEmpty())
221  {
223  }
224 
225  if (!cmdline.toString("geometry").isEmpty())
226  {
228  }
229 
230  QString filename = "";
231  if (!cmdline.toString("infile").isEmpty())
232  filename = cmdline.toString("infile");
233  else if (!cmdline.GetArgs().empty())
234  filename = cmdline.GetArgs()[0];
235 
237  if (!gContext->Init())
238  {
239  LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
241  }
242 
244 
245  QString themename = gCoreContext->GetSetting("Theme");
246  QString themedir = GetMythUI()->FindThemeDir(themename);
247  if (themedir.isEmpty())
248  {
249  QString msg = QString("Fatal Error: Couldn't find theme '%1'.")
250  .arg(themename);
251  LOG(VB_GENERAL, LOG_ERR, msg);
252  return GENERIC_EXIT_NO_THEME;
253  }
254 
255  GetMythUI()->LoadQtConfig();
256 
257 #if defined(Q_OS_MACX)
258  // Mac OS X doesn't define the AudioOutputDevice setting
259 #else
260  QString auddevice = gCoreContext->GetSetting("AudioOutputDevice");
261  if (auddevice.isEmpty())
262  {
263  LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Audio not configured, you need "
264  "to run 'mythfrontend', not 'mythtv'.");
266  }
267 #endif
268 
269  MythMainWindow *mainWindow = GetMythMainWindow();
270  mainWindow->Init();
271 
272 #ifndef _WIN32
273  QList<int> signallist;
274  signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
275  << SIGILL;
276 #if ! CONFIG_DARWIN
277  signallist << SIGRTMIN;
278 #endif
279  SignalHandler::Init(signallist);
280  signal(SIGHUP, SIG_IGN);
281 #endif
282 
283  if (cmdline.toBool("test"))
284  {
285  int seconds = 5;
286  if (!cmdline.toString("seconds").isEmpty())
287  seconds = cmdline.toInt("seconds");
288  auto *test = new VideoPerformanceTest(filename,
289  cmdline.toBool("nodecode"),
290  cmdline.toBool("decodeonly"), seconds,
291  cmdline.toBool("deinterlace"),
292  cmdline.toBool("gpu"));
293  test->Test();
294  delete test;
295  }
296  else
297  {
298  TV::InitKeys();
299  setHttpProxy();
300 
301  if (!UpgradeTVDatabaseSchema(false))
302  {
303  LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Incorrect database schema.");
304  delete gContext;
306  }
307 
308  if (filename.isEmpty())
309  {
310  TV::StartTV(nullptr, kStartTVNoFlags);
311  }
312  else
313  {
314  ProgramInfo pginfo(filename);
315  TV::StartTV(&pginfo, kStartTVNoFlags);
316  }
317  }
319 
320  delete gContext;
321 
323 
324  return GENERIC_EXIT_OK;
325 }
326 
327 /* vim: set expandtab tabstop=4 shiftwidth=4: */
static void ConfigureQtGUI(int SwapInterval=1)
Shared static initialistaion code for all MythTV GUI applications.
Startup context for MythTV.
Definition: mythcontext.h:42
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: mythvideoout.h:32
QString FindThemeDir(const QString &themename, bool doFallback=true)
Returns the full path to the theme denoted by themename.
def scan(profile, smoonURL, gate)
Definition: scan.py:57
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:847
static QString themedir
Definition: mythdirs.cpp:21
PlayerFlags
Definition: mythplayer.h:87
void LoadQtConfig(void)
virtual void Show(FrameScanType)=0
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
static void PrintVersion(void)
Print application version information.
virtual void StartDisplayingFrame(void)
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
void PrintHelp(void) const
Print command line option help.
static void Init(QList< int > &signallist, QObject *parent=nullptr)
void DestroyMythMainWindow(void)
FrameScanType
Definition: videoouttypes.h:78
virtual void PrepareFrame(VideoFrame *Frame, FrameScanType, OSD *Osd)=0
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:62
virtual void ProcessFrame(VideoFrame *Frame, OSD *Osd, const PIPMap &PipPlayers, FrameScanType Scan=kScan_Ignore)=0
int main(int argc, char *argv[])
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, int Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
MythDeintType
Definition: mythframe.h:120
static void SetX11Display(const QString &display)
This needs to be set before MythUIHelper is initialized so that the MythUIHelper::Init() can detect X...
void ApplySettingsOverride(void)
Apply all overrides to the global context.
Holds information on recordings and videos.
Definition: programinfo.h:67
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
QString GetSetting(const QString &key, const QString &defaultval="")
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void ParseGeometryOverride(const QString &geometry)
Parse an X11 style command line geometry string.
virtual QString GetCodecDecoderName(void) const =0
static void Done(void)
MythCommFlagCommandLineParser cmdline
MythUIHelper * GetMythUI()
MythMainWindow * GetMythMainWindow(void)
static bool StartTV(ProgramInfo *tvrec, uint flags, const ChannelInfoList &selection=ChannelInfoList())
returns true if the recording completed when exiting.
Definition: tv_play.cpp:290
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
#define MYTH_APPNAME_MYTHAVTEST
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
#define SIGHUP
Definition: compat.h:213
#define GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
Definition: exitcodes.h:21
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:16
bool Init(bool gui=true, bool promptForBackend=false, bool disableAutoDiscovery=false, bool ignoreDB=false)
virtual VideoFrame * GetLastShownFrame(void)
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
#define GENERIC_EXIT_NO_THEME
No Theme available.
Definition: exitcodes.h:14
#define GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:13
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:15
void Init(bool mayReInit=true)
VideoPerformanceTest(QString filename, bool decodeno, bool onlydecode, int runfor, bool deint, bool gpu)
static void InitKeys(void)
Definition: tv_play.cpp:504
virtual void DoneDisplayingFrame(VideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
#define GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
Definition: exitcodes.h:16
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
Definition: dbcheck.cpp:362
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23