00001 #include <unistd.h>
00002 #include <iostream>
00003
00004 using namespace std;
00005
00006 #include <QString>
00007 #include <QRegExp>
00008 #include <QDir>
00009 #include <QApplication>
00010 #include <QTime>
00011
00012 #include "tv_play.h"
00013 #include "programinfo.h"
00014 #include "commandlineparser.h"
00015 #include "mythplayer.h"
00016 #include "jitterometer.h"
00017
00018 #include "exitcodes.h"
00019 #include "mythcontext.h"
00020 #include "mythversion.h"
00021 #include "mythdbcon.h"
00022 #include "compat.h"
00023 #include "dbcheck.h"
00024 #include "mythlogging.h"
00025
00026
00027 #include "mythuihelper.h"
00028 #include "mythmainwindow.h"
00029
00030 class VideoPerformanceTest
00031 {
00032 public:
00033 VideoPerformanceTest(const QString &filename, bool novsync, bool onlydecode,
00034 int runfor, bool deint)
00035 : file(filename), novideosync(novsync), decodeonly(onlydecode),
00036 secondstorun(runfor), deinterlace(deint), ctx(NULL)
00037 {
00038 if (secondstorun < 1)
00039 secondstorun = 1;
00040 if (secondstorun > 3600)
00041 secondstorun = 3600;
00042 }
00043
00044 ~VideoPerformanceTest()
00045 {
00046 delete ctx;
00047 }
00048
00049 void Test(void)
00050 {
00051 PIPMap dummy;
00052
00053 if (novideosync)
00054 LOG(VB_GENERAL, LOG_INFO, "Will attempt to disable sync-to-vblank.");
00055
00056 RingBuffer *rb = RingBuffer::Create(file, false, true, 2000);
00057 MythPlayer *mp = new MythPlayer(kAudioMuted);
00058 mp->GetAudio()->SetAudioInfo("NULL", "NULL", 0, 0);
00059 mp->GetAudio()->SetNoAudio();
00060 ctx = new PlayerContext("VideoPerformanceTest");
00061 ctx->SetRingBuffer(rb);
00062 ctx->SetPlayer(mp);
00063 ctx->SetPlayingInfo(new ProgramInfo(file));
00064 mp->SetPlayerInfo(NULL, GetMythMainWindow(), ctx);
00065 FrameScanType scan = deinterlace ? kScan_Interlaced : kScan_Progressive;
00066 if (!mp->StartPlaying())
00067 {
00068 LOG(VB_GENERAL, LOG_ERR, "Failed to start playback.");
00069 return;
00070 }
00071
00072 VideoOutput *vo = mp->GetVideoOutput();
00073 if (!vo)
00074 {
00075 LOG(VB_GENERAL, LOG_ERR, "No video output.");
00076 return;
00077 }
00078
00079 LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
00080 LOG(VB_GENERAL, LOG_INFO, QString("Starting video performance test for '%1'.")
00081 .arg(file));
00082 LOG(VB_GENERAL, LOG_INFO, QString("Test will run for %1 seconds.")
00083 .arg(secondstorun));
00084
00085 if (decodeonly)
00086 LOG(VB_GENERAL, LOG_INFO, "Decoding frames only - skipping display.");
00087 LOG(VB_GENERAL, LOG_INFO, QString("Deinterlacing %1")
00088 .arg(deinterlace ? "enabled" : "disabled"));
00089
00090 Jitterometer *jitter = new Jitterometer("Performance: ", mp->GetFrameRate());
00091
00092 int ms = secondstorun * 1000;
00093 QTime start = QTime::currentTime();
00094 while (1)
00095 {
00096 int duration = start.msecsTo(QTime::currentTime());
00097 if (duration < 0 || duration > ms)
00098 {
00099 LOG(VB_GENERAL, LOG_INFO, "Complete.");
00100 break;
00101 }
00102
00103 if (mp->IsErrored())
00104 {
00105 LOG(VB_GENERAL, LOG_ERR, "Playback error.");
00106 break;
00107 }
00108
00109 if (mp->GetEof())
00110 {
00111 LOG(VB_GENERAL, LOG_INFO, "End of file.");
00112 break;
00113 }
00114
00115 if (!mp->PrebufferEnoughFrames())
00116 continue;
00117
00118 mp->SetBuffering(false);
00119 vo->StartDisplayingFrame();
00120 VideoFrame *frame = vo->GetLastShownFrame();
00121 mp->CheckAspectRatio(frame);
00122
00123 if (!decodeonly)
00124 {
00125 vo->ProcessFrame(frame, NULL, NULL, dummy, scan);
00126 vo->PrepareFrame(frame, scan, NULL);
00127 vo->Show(scan);
00128 }
00129 vo->DoneDisplayingFrame(frame);
00130 jitter->RecordCycleTime();
00131 }
00132 LOG(VB_GENERAL, LOG_INFO, "-----------------------------------");
00133 delete jitter;
00134 }
00135
00136 private:
00137 QString file;
00138 bool novideosync;
00139 bool decodeonly;
00140 int secondstorun;
00141 bool deinterlace;
00142 PlayerContext *ctx;
00143 };
00144
00145 int main(int argc, char *argv[])
00146 {
00147 MythAVTestCommandLineParser cmdline;
00148 if (!cmdline.Parse(argc, argv))
00149 {
00150 cmdline.PrintHelp();
00151 return GENERIC_EXIT_INVALID_CMDLINE;
00152 }
00153
00154 if (cmdline.toBool("showhelp"))
00155 {
00156 cmdline.PrintHelp();
00157 return GENERIC_EXIT_OK;
00158 }
00159
00160 if (cmdline.toBool("showversion"))
00161 {
00162 cmdline.PrintVersion();
00163 return GENERIC_EXIT_OK;
00164 }
00165
00166 QApplication a(argc, argv);
00167 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHAVTEST);
00168
00169 int retval;
00170 if ((retval = cmdline.ConfigureLogging()) != GENERIC_EXIT_OK)
00171 return retval;
00172
00173 if (!cmdline.toString("display").isEmpty())
00174 {
00175 MythUIHelper::SetX11Display(cmdline.toString("display"));
00176 }
00177
00178 if (!cmdline.toString("geometry").isEmpty())
00179 {
00180 MythUIHelper::ParseGeometryOverride(cmdline.toString("geometry"));
00181 }
00182
00183 QString filename = "";
00184 if (!cmdline.toString("infile").isEmpty())
00185 filename = cmdline.toString("infile");
00186 else if (cmdline.GetArgs().size() >= 1)
00187 filename = cmdline.GetArgs()[0];
00188
00189 gContext = new MythContext(MYTH_BINARY_VERSION);
00190 if (!gContext->Init())
00191 {
00192 LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
00193 return GENERIC_EXIT_NO_MYTHCONTEXT;
00194 }
00195
00196 cmdline.ApplySettingsOverride();
00197
00198 setuid(getuid());
00199
00200 QString themename = gCoreContext->GetSetting("Theme");
00201 QString themedir = GetMythUI()->FindThemeDir(themename);
00202 if (themedir.isEmpty())
00203 {
00204 QString msg = QString("Fatal Error: Couldn't find theme '%1'.")
00205 .arg(themename);
00206 LOG(VB_GENERAL, LOG_ERR, msg);
00207 return GENERIC_EXIT_NO_THEME;
00208 }
00209
00210 GetMythUI()->LoadQtConfig();
00211
00212 #if defined(Q_OS_MACX)
00213
00214 #else
00215 QString auddevice = gCoreContext->GetSetting("AudioOutputDevice");
00216 if (auddevice.isEmpty())
00217 {
00218 LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Audio not configured, you need "
00219 "to run 'mythfrontend', not 'mythtv'.");
00220 return GENERIC_EXIT_SETUP_ERROR;
00221 }
00222 #endif
00223
00224 MythMainWindow *mainWindow = GetMythMainWindow();
00225 mainWindow->Init();
00226
00227 if (cmdline.toBool("test"))
00228 {
00229 int seconds = 5;
00230 if (!cmdline.toString("seconds").isEmpty())
00231 seconds = cmdline.toInt("seconds");
00232 VideoPerformanceTest *test = new VideoPerformanceTest(filename, false,
00233 cmdline.toBool("decodeonly"), seconds,
00234 cmdline.toBool("deinterlace"));
00235 test->Test();
00236 delete test;
00237 }
00238 else
00239 {
00240 TV::InitKeys();
00241
00242 if (!UpgradeTVDatabaseSchema(false))
00243 {
00244 LOG(VB_GENERAL, LOG_ERR, "Fatal Error: Incorrect database schema.");
00245 delete gContext;
00246 return GENERIC_EXIT_DB_OUTOFDATE;
00247 }
00248
00249 if (filename.isEmpty())
00250 {
00251 TV::StartTV(NULL, kStartTVNoFlags);
00252 }
00253 else
00254 {
00255 ProgramInfo pginfo(filename);
00256 TV::StartTV(&pginfo, kStartTVNoFlags);
00257 }
00258 }
00259 DestroyMythMainWindow();
00260
00261 delete gContext;
00262
00263 return GENERIC_EXIT_OK;
00264 }
00265
00266