MythTV  master
mythtv/programs/mythavtest/main.cpp
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <iostream>
3 
4 using namespace std;
5 
6 #include <QString>
7 #include <QRegExp>
8 #include <QDir>
9 #include <QApplication>
10 #include <QTime>
11 
12 #include "tv_play.h"
13 #include "programinfo.h"
14 #include "commandlineparser.h"
15 #include "mythplayer.h"
16 #include "jitterometer.h"
17 
18 #include "exitcodes.h"
19 #include "mythcontext.h"
20 #include "mythversion.h"
21 #include "mythdbcon.h"
22 #include "compat.h"
23 #include "dbcheck.h"
24 #include "mythlogging.h"
25 #include "signalhandling.h"
26 #include "mythmiscutil.h"
27 #include "videooutbase.h"
28 
29 // libmythui
30 #include "mythuihelper.h"
31 #include "mythmainwindow.h"
32 
34 {
35  public:
36  VideoPerformanceTest(const QString &filename, bool novsync, bool onlydecode,
37  int runfor, bool deint, bool gpu)
38  : file(filename), novideosync(novsync), decodeonly(onlydecode),
39  secondstorun(runfor), deinterlace(deint), allowgpu(gpu), ctx(nullptr)
40  {
41  if (secondstorun < 1)
42  secondstorun = 1;
43  if (secondstorun > 3600)
44  secondstorun = 3600;
45  }
46 
48  {
49  delete ctx;
50  }
51 
52  void Test(void)
53  {
54  PIPMap dummy;
55 
56  if (novideosync) // TODO
57  LOG(VB_GENERAL, LOG_INFO, "Will attempt to disable sync-to-vblank.");
58 
59  RingBuffer *rb = RingBuffer::Create(file, false, true, 2000);
61  mp->GetAudio()->SetAudioInfo("NULL", "NULL", 0, 0);
62  mp->GetAudio()->SetNoAudio();
63  ctx = new PlayerContext("VideoPerformanceTest");
64  ctx->SetRingBuffer(rb);
65  ctx->SetPlayer(mp);
66  ProgramInfo *pinfo = new ProgramInfo(file);
67  ctx->SetPlayingInfo(pinfo); // makes a copy
68  delete pinfo;
69  mp->SetPlayerInfo(nullptr, GetMythMainWindow(), ctx);
70 
72  if (!mp->StartPlaying())
73  {
74  LOG(VB_GENERAL, LOG_ERR, "Failed to start playback.");
75  return;
76  }
77 
78  VideoOutput *vo = mp->GetVideoOutput();
79  if (!vo)
80  {
81  LOG(VB_GENERAL, LOG_ERR, "No video output.");
82  return;
83  }
84 
85  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
86  LOG(VB_GENERAL, LOG_INFO, "Ensure Sync to VBlank is disabled.");
87  LOG(VB_GENERAL, LOG_INFO, "Otherwise rate will be limited to that of the display.");
88  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
89  LOG(VB_GENERAL, LOG_INFO, QString("Starting video performance test for '%1'.")
90  .arg(file));
91  LOG(VB_GENERAL, LOG_INFO, QString("Test will run for %1 seconds.")
92  .arg(secondstorun));
93 
94  if (decodeonly)
95  LOG(VB_GENERAL, LOG_INFO, "Decoding frames only - skipping display.");
96 
97  bool doublerate = vo->NeedsDoubleFramerate();
98  if (deinterlace)
99  {
100  LOG(VB_GENERAL, LOG_INFO, QString("Deinterlacing: %1")
101  .arg(doublerate ? "doublerate" : "singlerate"));
102  if (doublerate)
103  LOG(VB_GENERAL, LOG_INFO, "Output will show fields per second");
104  }
105  else
106  {
107  LOG(VB_GENERAL, LOG_INFO, "Deinterlacing disabled");
108  }
109 
110  DecoderBase* dec = mp->GetDecoder();
111  if (dec)
112  LOG(VB_GENERAL, LOG_INFO, QString("Using decoder: %1").arg(dec->GetCodecDecoderName()));
113 
114  Jitterometer *jitter = new Jitterometer("Performance: ", mp->GetFrameRate() * (doublerate ? 2 : 1));
115 
116  int ms = secondstorun * 1000;
117  QTime start = QTime::currentTime();
118  while (true)
119  {
120  int duration = start.msecsTo(QTime::currentTime());
121  if (duration < 0 || duration > ms)
122  {
123  LOG(VB_GENERAL, LOG_INFO, "Complete.");
124  break;
125  }
126 
127  if (mp->IsErrored())
128  {
129  LOG(VB_GENERAL, LOG_ERR, "Playback error.");
130  break;
131  }
132 
133  if (mp->GetEof() != kEofStateNone)
134  {
135  LOG(VB_GENERAL, LOG_INFO, "End of file.");
136  break;
137  }
138 
139  if (!mp->PrebufferEnoughFrames())
140  continue;
141 
142  mp->SetBuffering(false);
143  vo->StartDisplayingFrame();
144  VideoFrame *frame = vo->GetLastShownFrame();
145  mp->CheckAspectRatio(frame);
146 
147  if (!decodeonly)
148  {
149  vo->ProcessFrame(frame, nullptr, nullptr, dummy, scan);
150  vo->PrepareFrame(frame, scan, nullptr);
151  vo->Show(scan);
152 
153  if (vo->NeedsDoubleFramerate() && deinterlace)
154  {
155  vo->PrepareFrame(frame, kScan_Intr2ndField, nullptr);
156  vo->Show(scan);
157  }
158  }
159  vo->DoneDisplayingFrame(frame);
160  jitter->RecordCycleTime();
161  }
162  LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
163  delete jitter;
164  }
165 
166  private:
167  QString file;
172  bool allowgpu;
174 };
175 
176 int main(int argc, char *argv[])
177 {
178 
179 #if CONFIG_OMX_RPI
180  setenv("QT_XCB_GL_INTEGRATION","none",0);
181 #endif
182 
183  // try and disable sync to vblank on linux x11
184  qputenv("vblank_mode", "0"); // Intel and AMD
185  qputenv("__GL_SYNC_TO_VBLANK", "0"); // NVidia
186 
188  if (!cmdline.Parse(argc, argv))
189  {
190  cmdline.PrintHelp();
192  }
193 
194  if (cmdline.toBool("showhelp"))
195  {
196  cmdline.PrintHelp();
197  return GENERIC_EXIT_OK;
198  }
199 
200  if (cmdline.toBool("showversion"))
201  {
203  return GENERIC_EXIT_OK;
204  }
205 
206  QApplication a(argc, argv);
207  QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHAVTEST);
208 
209  int retval;
210  if ((retval = cmdline.ConfigureLogging()) != GENERIC_EXIT_OK)
211  return retval;
212 
213  if (!cmdline.toString("display").isEmpty())
214  {
216  }
217 
218  if (!cmdline.toString("geometry").isEmpty())
219  {
221  }
222 
223  QString filename = "";
224  if (!cmdline.toString("infile").isEmpty())
225  filename = cmdline.toString("infile");
226  else if (!cmdline.GetArgs().empty())
227  filename = cmdline.GetArgs()[0];
228 
230  if (!gContext->Init())
231  {
232  LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
234  }
235 
237 
238  QString themename = gCoreContext->GetSetting("Theme");
239  QString themedir = GetMythUI()->FindThemeDir(themename);
240  if (themedir.isEmpty())
241  {
242  QString msg = QString("Fatal Error: Couldn't find theme '%1'.")
243  .arg(themename);
244  LOG(VB_GENERAL, LOG_ERR, msg);
245  return GENERIC_EXIT_NO_THEME;
246  }
247 
248  GetMythUI()->LoadQtConfig();
249 
250 #if defined(Q_OS_MACX)
251  // Mac OS X doesn't define the AudioOutputDevice setting
252 #else
253  QString auddevice = gCoreContext->GetSetting("AudioOutputDevice");
254  if (auddevice.isEmpty())
255  {
256  LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Audio not configured, you need "
257  "to run 'mythfrontend', not 'mythtv'.");
259  }
260 #endif
261 
262  MythMainWindow *mainWindow = GetMythMainWindow();
263 #if CONFIG_DARWIN
264  mainWindow->Init(OPENGL2_PAINTER);
265 #else
266  mainWindow->Init();
267 #endif
268 
269 #ifndef _WIN32
270  QList<int> signallist;
271  signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
272  << SIGILL;
273 #if ! CONFIG_DARWIN
274  signallist << SIGRTMIN;
275 #endif
276  SignalHandler::Init(signallist);
277  signal(SIGHUP, SIG_IGN);
278 #endif
279 
280  if (cmdline.toBool("test"))
281  {
282  int seconds = 5;
283  if (!cmdline.toString("seconds").isEmpty())
284  seconds = cmdline.toInt("seconds");
285  VideoPerformanceTest *test = new VideoPerformanceTest(filename, false,
286  cmdline.toBool("decodeonly"), seconds,
287  cmdline.toBool("deinterlace"),
288  cmdline.toBool("gpu"));
289  test->Test();
290  delete test;
291  }
292  else
293  {
294  TV::InitKeys();
295  setHttpProxy();
296 
297  if (!UpgradeTVDatabaseSchema(false))
298  {
299  LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Incorrect database schema.");
300  delete gContext;
302  }
303 
304  if (filename.isEmpty())
305  {
306  TV::StartTV(nullptr, kStartTVNoFlags);
307  }
308  else
309  {
310  ProgramInfo pginfo(filename);
311  TV::StartTV(&pginfo, kStartTVNoFlags);
312  }
313  }
315 
316  delete gContext;
317 
319 
320  return GENERIC_EXIT_OK;
321 }
322 
323 /* vim: set expandtab tabstop=4 shiftwidth=4: */
Startup context for MythTV.
Definition: mythcontext.h:42
QString FindThemeDir(const QString &themename, bool doFallback=true)
Returns the full path to the theme denoted by themename.
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
def scan(profile, smoonURL, gate)
Definition: scan.py:43
static QString themedir
Definition: mythdirs.cpp:21
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: videooutbase.h:37
PlayerFlags
Definition: mythplayer.h:88
void LoadQtConfig(void)
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
VideoOutput * GetVideoOutput(void)
Definition: mythplayer.h:244
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.
virtual bool NeedsDoubleFramerate(void) const
Should Prepare() and Show() be called twice for every ProcessFrame().
virtual bool StartPlaying(void)
void PrintHelp(void) const
Print command line option help.
void SetAudioInfo(const QString &main_device, const QString &passthru_device, uint samplerate, int codec_profile=-1)
Set audio output device parameters.
static void Init(QList< int > &signallist, QObject *parent=nullptr)
virtual void PrepareFrame(VideoFrame *buffer, FrameScanType, OSD *osd)=0
void DestroyMythMainWindow(void)
void SetNoAudio(void)
Definition: audioplayer.h:51
FrameScanType
Definition: videoouttypes.h:80
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static RingBuffer * Create(const QString &xfilename, bool write, bool usereadahead=true, int timeout_ms=kDefaultOpenTimeout, bool stream_only=false)
Creates a RingBuffer instance.
Definition: ringbuffer.cpp:104
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:63
void Init(const QString &forcedpainter=QString(), bool mayReInit=true)
int main(int argc, char *argv[])
VideoPerformanceTest(const QString &filename, bool novsync, bool onlydecode, int runfor, bool deint, bool gpu)
static void SetX11Display(const QString &display)
This needs to be set before MythUIHelper is initialized so that the MythUIHelper::Init() can detect X...
#define OPENGL2_PAINTER
Definition: mythuidefines.h:4
virtual void StartDisplayingFrame(void)
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
Definition: videooutbase.h:217
void ApplySettingsOverride(void)
Apply all overrides to the global context.
This class serves as the base class for all video output methods.
Definition: videooutbase.h:46
Holds information on recordings and videos.
Definition: programinfo.h:66
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
AudioPlayer * GetAudio(void)
Definition: mythplayer.h:189
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.
float GetFrameRate(void) const
Definition: mythplayer.h:176
EofState GetEof(void) const
static void ParseGeometryOverride(const QString &geometry)
Parse an X11 style command line geometry string.
bool RecordCycleTime()
virtual void ProcessFrame(VideoFrame *frame, OSD *osd, FilterChain *filterList, const PIPMap &pipPlayers, FrameScanType scan=kScan_Ignore)=0
virtual QString GetCodecDecoderName(void) const =0
static void Done(void)
bool IsErrored(void) const
MythCommFlagCommandLineParser cmdline
MythUIHelper * GetMythUI()
virtual void Show(FrameScanType)=0
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
virtual void DoneDisplayingFrame(VideoFrame *frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
Definition: videooutbase.h:220
void SetPlayerInfo(TV *tv, QWidget *widget, PlayerContext *ctx)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
#define MYTH_APPNAME_MYTHAVTEST
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
virtual VideoFrame * GetLastShownFrame(void)
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
Definition: videooutbase.h:239
void SetBuffering(bool new_buffering)
#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
virtual bool PrebufferEnoughFrames(int min_buffers=0)
#define setenv(x, y, z)
Definition: compat.h:156
bool Init(const bool gui=true, const bool promptForBackend=false, const bool disableAutoDiscovery=false, const bool ignoreDB=false)
Implements a file/stream reader/writer.
#define GENERIC_EXIT_NO_THEME
No Theme available.
Definition: exitcodes.h:14
int ConfigureLogging(QString mask="general", unsigned int progress=0)
Read in logging options and initialize the logging interface.
#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
static void InitKeys(void)
Definition: tv_play.cpp:505
void PrintVersion(void) const
Print application version information.
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:278
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
void CheckAspectRatio(VideoFrame *frame)
#define GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
Definition: exitcodes.h:16