From 171f8116696d47abde095e526d697a59a9697b61 Mon Sep 17 00:00:00 2001 From: Clayton Groeneveld Date: Wed, 13 Mar 2019 05:27:36 -0500 Subject: [PATCH] UI: Estimate recording time left until disk is full --- UI/data/locale/en-US.ini | 2 ++ UI/window-basic-stats.cpp | 74 ++++++++++++++++++++++++++++++++++++--- UI/window-basic-stats.hpp | 15 ++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index e60232a27..fdaf7296c 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -87,6 +87,7 @@ VerticalLayout="Vertical Layout" Group="Group" DoNotShowAgain="Do not show again" Default="(Default)" +Calculating="Calculating..." # warning if program already open AlreadyRunning.Title="OBS is already running" @@ -200,6 +201,7 @@ Basic.Stats.Status.Inactive="Inactive" Basic.Stats.DroppedFrames="Dropped Frames (Network)" Basic.Stats.MegabytesSent="Total Data Output" Basic.Stats.Bitrate="Bitrate" +Basic.Stats.DiskFullIn="Disk full in (approx.)" ResetUIWarning.Title="Are you sure you want to reset the UI?" ResetUIWarning.Text="Resetting the UI will hide additional docks. You will need to unhide these docks from the view menu if you want them to be visible.\n\nAre you sure you want to reset the UI?" diff --git a/UI/window-basic-stats.cpp b/UI/window-basic-stats.cpp index eb96f1be2..3cc7e2925 100644 --- a/UI/window-basic-stats.cpp +++ b/UI/window-basic-stats.cpp @@ -4,6 +4,7 @@ #include "window-basic-main.hpp" #include "platform.hpp" #include "obs-app.hpp" +#include "qt-wrappers.hpp" #include #include @@ -15,6 +16,7 @@ #include #define TIMER_INTERVAL 2000 +#define REC_TIME_LEFT_INTERVAL 30000 static void setThemeID(QWidget *widget, const QString &themeID) { @@ -28,15 +30,32 @@ static void setThemeID(QWidget *widget, const QString &themeID) } } +void OBSBasicStats::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) +{ + OBSBasicStats *stats = reinterpret_cast(ptr); + + switch ((int)event) { + case OBS_FRONTEND_EVENT_RECORDING_STARTED: + stats->StartRecTimeLeft(); + break; + case OBS_FRONTEND_EVENT_RECORDING_STOPPED: + stats->ResetRecTimeLeft(); + break; + } +} + OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) : QWidget (parent), cpu_info (os_cpu_usage_info_start()), - timer (this) + timer (this), + recTimeLeft (this) { QVBoxLayout *mainLayout = new QVBoxLayout(); QGridLayout *topLayout = new QGridLayout(); outputLayout = new QGridLayout(); + bitrates.reserve(REC_TIME_LEFT_INTERVAL / TIMER_INTERVAL); + int row = 0; auto newStatBare = [&] (QString name, QWidget *label, int col) @@ -57,10 +76,12 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) cpuUsage = new QLabel(this); hddSpace = new QLabel(this); + recordTimeLeft = new QLabel(this); memUsage = new QLabel(this); newStat("CPUUsage", cpuUsage, 0); newStat("HDDSpaceAvailable", hddSpace, 0); + newStat("DiskFullIn", recordTimeLeft, 0); newStat("MemoryUsage", memUsage, 0); fps = new QLabel(this); @@ -152,6 +173,11 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) Update(); + QObject::connect(&recTimeLeft, &QTimer::timeout, this, + &OBSBasicStats::RecordingTimeLeft); + recTimeLeft.setInterval(REC_TIME_LEFT_INTERVAL); + recTimeLeft.start(); + OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); const char *geometry = config_get_string(main->Config(), @@ -170,6 +196,8 @@ OBSBasicStats::OBSBasicStats(QWidget *parent, bool closeable) size(), rect)); } } + + obs_frontend_add_event_callback(OBSFrontendEvent, this); } void OBSBasicStats::closeEvent(QCloseEvent *event) @@ -280,7 +308,7 @@ void OBSBasicStats::Update() #define MBYTE (1024ULL * 1024ULL) #define GBYTE (1024ULL * 1024ULL * 1024ULL) #define TBYTE (1024ULL * 1024ULL * 1024ULL * 1024ULL) - uint64_t num_bytes = os_get_free_disk_space(path); + num_bytes = os_get_free_disk_space(path); QString abrv = QStringLiteral(" MB"); long double num; @@ -393,6 +421,45 @@ void OBSBasicStats::Update() outputLabels[0].Update(strOutput, false); outputLabels[1].Update(recOutput, true); + + if (obs_output_active(recOutput)) { + long double kbps = outputLabels[1].kbps; + bitrates.push_back(kbps); + } +} + +void OBSBasicStats::StartRecTimeLeft() +{ + recordTimeLeft->setText(QTStr("Calculating")); + recTimeLeft.start(); +} + +void OBSBasicStats::ResetRecTimeLeft() +{ + bitrates.clear(); + recTimeLeft.stop(); + recordTimeLeft->setText(QTStr("")); +} + +void OBSBasicStats::RecordingTimeLeft() +{ + long double averageBitrate = accumulate(bitrates.begin(), + bitrates.end(), 0.0) / + (long double)bitrates.size(); + long double bytesPerSec = (averageBitrate / 8.0l) * 1000.0l; + long double secondsUntilFull = (long double)num_bytes / bytesPerSec; + + bitrates.clear(); + + int totalMinutes = (int)secondsUntilFull / 60; + int minutes = totalMinutes % 60; + int hours = totalMinutes / 60; + + QString text; + text.sprintf("%d %s, %d %s", hours, QT_TO_UTF8(QTStr("Hours")), + minutes, QT_TO_UTF8(QTStr("Minutes"))); + recordTimeLeft->setText(text); + recordTimeLeft->setMinimumWidth(recordTimeLeft->width()); } void OBSBasicStats::Reset() @@ -428,8 +495,7 @@ void OBSBasicStats::OutputLabels::Update(obs_output_t *output, bool rec) uint64_t bitsBetween = (bytesSent - lastBytesSent) * 8; long double timePassed = (long double)(curTime - lastBytesSentTime) / 1000000000.0l; - long double kbps = (long double)bitsBetween / - timePassed / 1000.0l; + kbps = (long double)bitsBetween / timePassed / 1000.0l; if (timePassed < 0.01l) kbps = 0.0l; diff --git a/UI/window-basic-stats.hpp b/UI/window-basic-stats.hpp index 983376e30..8a44e423e 100644 --- a/UI/window-basic-stats.hpp +++ b/UI/window-basic-stats.hpp @@ -17,6 +17,7 @@ class OBSBasicStats : public QWidget { QLabel *fps = nullptr; QLabel *cpuUsage = nullptr; QLabel *hddSpace = nullptr; + QLabel *recordTimeLeft = nullptr; QLabel *memUsage = nullptr; QLabel *renderTime = nullptr; @@ -28,6 +29,9 @@ class OBSBasicStats : public QWidget { os_cpu_usage_info_t *cpu_info = nullptr; QTimer timer; + QTimer recTimeLeft; + uint64_t num_bytes = 0; + std::vector bitrates; struct OutputLabels { QPointer name; @@ -44,6 +48,8 @@ class OBSBasicStats : public QWidget { void Update(obs_output_t *output, bool rec); void Reset(obs_output_t *output); + + long double kbps = 0.0l; }; QList outputLabels; @@ -54,14 +60,23 @@ class OBSBasicStats : public QWidget { virtual void closeEvent(QCloseEvent *event) override; + static void OBSFrontendEvent(enum obs_frontend_event event, void *ptr); + public: OBSBasicStats(QWidget *parent = nullptr, bool closable = true); ~OBSBasicStats(); static void InitializeValues(); + + void StartRecTimeLeft(); + void ResetRecTimeLeft(); + private: QPointer shortcutFilter; +private slots: + void RecordingTimeLeft(); + protected: virtual void showEvent(QShowEvent *event) override; virtual void hideEvent(QHideEvent *event) override;