MythTV master
mythavtest.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <unistd.h>
3#include <utility>
4
5#include <QtGlobal>
6#include <QApplication>
7#include <QDir>
8#include <QString>
9#include <QSurfaceFormat>
10#include <QTime>
11
12// libmyth*
13#include "libmyth/mythcontext.h"
14#include "libmythbase/compat.h"
21#include "libmythbase/mythversion.h"
23#include "libmythtv/dbcheck.h"
27#include "libmythtv/tv_play.h"
30
32
34{
35 public:
36 VideoPerformanceTest(QString filename, bool decodeno, bool onlydecode,
37 std::chrono::seconds runfor, bool deint, bool gpu)
38 : m_file(std::move(filename)),
39 m_noDecode(decodeno),
40 m_decodeOnly(onlydecode),
41 m_secondsToRun(std::clamp(runfor, 1s, 3600s)),
42 m_deinterlace(deint),
43 m_allowGpu(gpu)
44 {
45 }
46
48 {
49 delete m_ctx;
50 }
51
52 void Test(void)
53 {
54 MythMediaBuffer *rb = MythMediaBuffer::Create(m_file, false, true, 2s);
55 m_ctx = new PlayerContext("VideoPerformanceTest");
56 auto *mp = new MythPlayerUI(GetMythMainWindow(), nullptr, m_ctx, static_cast<PlayerFlags>(kAudioMuted | (m_allowGpu ? kDecodeAllowGPU: kNoFlags)));
57 mp->GetAudio()->SetAudioInfo("NULL", "NULL", 0, 0);
58 mp->GetAudio()->SetNoAudio();
60 m_ctx->SetPlayer(mp);
61 auto *pinfo = new ProgramInfo(m_file);
62 m_ctx->SetPlayingInfo(pinfo); // makes a copy
63 delete pinfo;
64
66 if (!mp->StartPlaying())
67 {
68 LOG(VB_GENERAL, LOG_ERR, "Failed to start playback.");
69 return;
70 }
71
72 MythVideoOutput *vo = mp->GetVideoOutput();
73 if (!vo)
74 {
75 LOG(VB_GENERAL, LOG_ERR, "No video output.");
76 return;
77 }
78
79 LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
80 LOG(VB_GENERAL, LOG_INFO, "Ensure Sync to VBlank is disabled.");
81 LOG(VB_GENERAL, LOG_INFO, "Otherwise rate will be limited to that of the display.");
82 LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
83 LOG(VB_GENERAL, LOG_INFO, QString("Starting video performance test for '%1'.")
84 .arg(m_file));
85 LOG(VB_GENERAL, LOG_INFO, QString("Test will run for %1 seconds.")
86 .arg(m_secondsToRun.count()));
87
88 if (m_noDecode)
89 LOG(VB_GENERAL, LOG_INFO, "No decode after startup - checking display performance");
90 else if (m_decodeOnly)
91 LOG(VB_GENERAL, LOG_INFO, "Decoding frames only - skipping display.");
92 DecoderBase* dec = mp->GetDecoder();
93 if (dec)
94 LOG(VB_GENERAL, LOG_INFO, QString("Using decoder: %1").arg(dec->GetCodecDecoderName()));
95
96 auto *jitter = new Jitterometer("Performance: ", static_cast<int>(mp->GetFrameRate()));
97
98 QTime start = QTime::currentTime();
99 MythVideoFrame *frame = nullptr;
100 while (true)
101 {
102 mp->ProcessCallbacks();
103 auto duration = std::chrono::milliseconds(start.msecsTo(QTime::currentTime()));
104 if (duration < 0ms || duration > m_secondsToRun)
105 {
106 LOG(VB_GENERAL, LOG_INFO, "Complete.");
107 break;
108 }
109
110 if (mp->IsErrored())
111 {
112 LOG(VB_GENERAL, LOG_ERR, "Playback error.");
113 break;
114 }
115
116 if (mp->GetEof() != kEofStateNone)
117 {
118 LOG(VB_GENERAL, LOG_INFO, "End of file.");
119 break;
120 }
121
122 if (!mp->PrebufferEnoughFrames())
123 continue;
124
125 mp->SetBuffering(false);
127 if ((m_noDecode && !frame) || !m_noDecode)
128 frame = vo->GetLastShownFrame();
129 mp->CheckAspectRatio(frame);
130
131 if (!m_decodeOnly)
132 {
134 vo->PrepareFrame(frame, scan);
135 vo->RenderFrame(frame, scan);
136 vo->EndFrame();
137
138 if (doubledeint && m_deinterlace)
139 {
140 doubledeint = frame->GetDoubleRateOption(DEINT_CPU);
142 if (doubledeint && !other)
145 vo->EndFrame();
146 }
147 }
148 if (!m_noDecode)
149 vo->DoneDisplayingFrame(frame);
150 jitter->RecordCycleTime();
151 }
152 LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
153 delete jitter;
154 }
155
156 private:
157 QString m_file;
158 bool m_noDecode {false};
159 bool m_decodeOnly {false};
160 std::chrono::seconds m_secondsToRun {1s};
161 bool m_deinterlace {false};
162 bool m_allowGpu {false};
164};
165
166int main(int argc, char *argv[])
167{
169 if (!cmdline.Parse(argc, argv))
170 {
173 }
174
175 if (cmdline.toBool("showhelp"))
176 {
178 return GENERIC_EXIT_OK;
179 }
180
181 if (cmdline.toBool("showversion"))
182 {
184 return GENERIC_EXIT_OK;
185 }
186
187 int swapinterval = 1;
188 if (cmdline.toBool("test"))
189 {
190 // try and disable sync to vblank on linux x11
191 qputenv("vblank_mode", "0"); // Intel and AMD
192 qputenv("__GL_SYNC_TO_VBLANK", "0"); // NVidia
193 // the default surface format has a swap interval of 1. This is used by
194 // the MythMainwindow widget that then drives vsync for all widgets/children
195 // (i.e. MythPainterWindow) and we cannot override it on some drivers. So
196 // force the default here.
197 swapinterval = 0;
198 }
199
201
202 QApplication a(argc, argv);
203 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHAVTEST);
204
205 int retval = cmdline.ConfigureLogging();
206 if (retval != GENERIC_EXIT_OK)
207 return retval;
208
209 if (!cmdline.toString("geometry").isEmpty())
211
212 QString filename = "";
213 if (!cmdline.toString("infile").isEmpty())
214 filename = cmdline.toString("infile");
215 else if (!cmdline.GetArgs().empty())
216 filename = cmdline.GetArgs().at(0);
217
218 MythContext context {MYTH_BINARY_VERSION, true};
219 if (!context.Init())
220 {
221 LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
223 }
224
226
227 QString themename = gCoreContext->GetSetting("Theme");
228 QString themedir = GetMythUI()->FindThemeDir(themename);
229 if (themedir.isEmpty())
230 {
231 QString msg = QString("Fatal Error: Couldn't find theme '%1'.")
232 .arg(themename);
233 LOG(VB_GENERAL, LOG_ERR, msg);
235 }
236
237#if defined(Q_OS_MACOS)
238 // Mac OS X doesn't define the AudioOutputDevice setting
239#else
240 QString auddevice = gCoreContext->GetSetting("AudioOutputDevice");
241 if (auddevice.isEmpty())
242 {
243 LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Audio not configured, you need "
244 "to run 'mythfrontend', not 'mythtv'.");
246 }
247#endif
248
249 MythMainWindow *mainWindow = GetMythMainWindow();
250 mainWindow->Init();
251
252 if (cmdline.toBool("test"))
253 {
254 std::chrono::seconds seconds = 5s;
255 if (!cmdline.toString("seconds").isEmpty())
256 seconds = std::chrono::seconds(cmdline.toInt("seconds"));
257 auto *test = new VideoPerformanceTest(filename,
258 cmdline.toBool("nodecode"),
259 cmdline.toBool("decodeonly"), seconds,
260 cmdline.toBool("deinterlace"),
261 cmdline.toBool("gpu"));
262 test->Test();
263 delete test;
264 }
265 else
266 {
267 TV::InitKeys();
268 setHttpProxy();
269
270 if (!UpgradeTVDatabaseSchema(false))
271 {
272 LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Incorrect database schema.");
274 }
275
276 if (filename.isEmpty())
277 {
279 }
280 else
281 {
282 ProgramInfo pginfo(filename);
284 }
285 }
286
287 return GENERIC_EXIT_OK;
288}
289
290/* vim: set expandtab tabstop=4 shiftwidth=4: */
virtual QString GetCodecDecoderName(void) const =0
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
void ApplySettingsOverride(void)
Apply all overrides to the global context.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
void PrintHelp(void) const
Print command line option help.
Startup context for MythTV.
Definition: mythcontext.h:20
QString GetSetting(const QString &key, const QString &defaultval="")
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialisation code for all MythTV GUI applications.
void Init(bool MayReInit=true)
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
static void ParseGeometryOverride(const QString &Geometry)
Parse an X11 style command line geometry string.
QString FindThemeDir(const QString &ThemeName, bool Fallback=true)
Returns the full path to the theme denoted by themename.
MythDeintType GetDoubleRateOption(MythDeintType Type, MythDeintType Override=DEINT_NONE) const
Definition: mythframe.cpp:449
virtual void StartDisplayingFrame()
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
virtual void EndFrame()=0
virtual void PrepareFrame(MythVideoFrame *Frame, FrameScanType Scan=kScan_Ignore)=0
virtual MythVideoFrame * GetLastShownFrame()
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
virtual void DoneDisplayingFrame(MythVideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
virtual void RenderFrame(MythVideoFrame *Frame, FrameScanType)=0
void SetRingBuffer(MythMediaBuffer *Buffer)
void SetPlayingInfo(const ProgramInfo *info)
assign programinfo to the context
void SetPlayer(MythPlayer *newplayer)
Holds information on recordings and videos.
Definition: programinfo.h:68
static bool StartTV(ProgramInfo *TVRec, uint Flags, const ChannelInfoList &Selection=ChannelInfoList())
Start playback of media.
Definition: tv_play.cpp:287
static void InitKeys()
Definition: tv_play.cpp:494
std::chrono::seconds m_secondsToRun
Definition: mythavtest.cpp:160
PlayerContext * m_ctx
Definition: mythavtest.cpp:163
VideoPerformanceTest(QString filename, bool decodeno, bool onlydecode, std::chrono::seconds runfor, bool deint, bool gpu)
Definition: mythavtest.cpp:36
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
Definition: dbcheck.cpp:362
@ kEofStateNone
Definition: decoderbase.h:69
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:16
@ GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
Definition: exitcodes.h:19
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
Definition: exitcodes.h:24
@ GENERIC_EXIT_NO_THEME
No Theme available.
Definition: exitcodes.h:17
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
static constexpr const char * MYTH_APPNAME_MYTHAVTEST
Definition: mythappname.h:16
int main(int argc, char *argv[])
Definition: mythavtest.cpp:166
MythCommFlagCommandLineParser cmdline
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static QString themedir
Definition: mythdirs.cpp:23
MythDeintType
Definition: mythframe.h:67
@ DEINT_DRIVER
Definition: mythframe.h:74
@ DEINT_SHADER
Definition: mythframe.h:73
@ DEINT_CPU
Definition: mythframe.h:72
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
PlayerFlags
Definition: mythplayer.h:65
@ kAudioMuted
Definition: mythplayer.h:74
@ kNoFlags
Definition: mythplayer.h:66
@ kDecodeAllowGPU
Definition: mythplayer.h:72
MythUIHelper * GetMythUI()
def scan(profile, smoonURL, gate)
Definition: scan.py:54
STL namespace.
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
@ kStartTVNoFlags
Definition: tv_play.h:114
FrameScanType
Definition: videoouttypes.h:95
@ kScan_Intr2ndField
Definition: videoouttypes.h:99
@ kScan_Interlaced
Definition: videoouttypes.h:98
@ kScan_Progressive