window-basic-status-bar.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include <QLabel>
  2. #include "obs-app.hpp"
  3. #include "window-basic-main.hpp"
  4. #include "window-basic-status-bar.hpp"
  5. #include "window-basic-main-outputs.hpp"
  6. OBSBasicStatusBar::OBSBasicStatusBar(QWidget *parent)
  7. : QStatusBar (parent),
  8. delayInfo (new QLabel),
  9. droppedFrames (new QLabel),
  10. sessionTime (new QLabel),
  11. cpuUsage (new QLabel),
  12. kbps (new QLabel)
  13. {
  14. sessionTime->setText(QString("00:00:00"));
  15. cpuUsage->setText(QString("CPU: 0.0%"));
  16. delayInfo->setAlignment(Qt::AlignRight);
  17. droppedFrames->setAlignment(Qt::AlignRight);
  18. sessionTime->setAlignment(Qt::AlignRight);
  19. cpuUsage->setAlignment(Qt::AlignRight);
  20. kbps->setAlignment(Qt::AlignRight);
  21. delayInfo->setIndent(20);
  22. droppedFrames->setIndent(20);
  23. sessionTime->setIndent(20);
  24. cpuUsage->setIndent(20);
  25. kbps->setIndent(10);
  26. addPermanentWidget(droppedFrames);
  27. addPermanentWidget(sessionTime);
  28. addPermanentWidget(cpuUsage);
  29. addPermanentWidget(delayInfo);
  30. addPermanentWidget(kbps);
  31. }
  32. void OBSBasicStatusBar::Activate()
  33. {
  34. if (!active) {
  35. refreshTimer = new QTimer(this);
  36. connect(refreshTimer, SIGNAL(timeout()),
  37. this, SLOT(UpdateStatusBar()));
  38. totalSeconds = 0;
  39. refreshTimer->start(1000);
  40. active = true;
  41. }
  42. }
  43. void OBSBasicStatusBar::Deactivate()
  44. {
  45. OBSBasic *main = qobject_cast<OBSBasic*>(parent());
  46. if (!main)
  47. return;
  48. if (!main->outputHandler->Active()) {
  49. delete refreshTimer;
  50. sessionTime->setText(QString("00:00:00"));
  51. delayInfo->setText("");
  52. droppedFrames->setText("");
  53. kbps->setText("");
  54. delaySecTotal = 0;
  55. delaySecStarting = 0;
  56. delaySecStopping = 0;
  57. active = false;
  58. }
  59. }
  60. void OBSBasicStatusBar::UpdateDelayMsg()
  61. {
  62. QString msg;
  63. if (delaySecTotal) {
  64. if (delaySecStarting && !delaySecStopping) {
  65. msg = QTStr("Basic.StatusBar.DelayStartingIn");
  66. msg = msg.arg(QString::number(delaySecStarting));
  67. } else if (!delaySecStarting && delaySecStopping) {
  68. msg = QTStr("Basic.StatusBar.DelayStoppingIn");
  69. msg = msg.arg(QString::number(delaySecStopping));
  70. } else if (delaySecStarting && delaySecStopping) {
  71. msg = QTStr("Basic.StatusBar.DelayStartingStoppingIn");
  72. msg = msg.arg(QString::number(delaySecStopping),
  73. QString::number(delaySecStarting));
  74. } else {
  75. msg = QTStr("Basic.StatusBar.Delay");
  76. msg = msg.arg(QString::number(delaySecTotal));
  77. }
  78. }
  79. delayInfo->setText(msg);
  80. }
  81. #define BITRATE_UPDATE_SECONDS 2
  82. void OBSBasicStatusBar::UpdateBandwidth()
  83. {
  84. if (!streamOutput)
  85. return;
  86. if (++bitrateUpdateSeconds < BITRATE_UPDATE_SECONDS)
  87. return;
  88. uint64_t bytesSent = obs_output_get_total_bytes(streamOutput);
  89. uint64_t bytesSentTime = os_gettime_ns();
  90. if (bytesSent == 0)
  91. lastBytesSent = 0;
  92. uint64_t bitsBetween = (bytesSent - lastBytesSent) * 8;
  93. double timePassed = double(bytesSentTime - lastBytesSentTime) /
  94. 1000000000.0;
  95. double kbitsPerSec = double(bitsBetween) / timePassed / 1000.0;
  96. QString text;
  97. text += QString("kb/s: ") +
  98. QString::number(kbitsPerSec, 'f', 0);
  99. kbps->setText(text);
  100. kbps->setMinimumWidth(kbps->width());
  101. lastBytesSent = bytesSent;
  102. lastBytesSentTime = bytesSentTime;
  103. bitrateUpdateSeconds = 0;
  104. }
  105. void OBSBasicStatusBar::UpdateCPUUsage()
  106. {
  107. OBSBasic *main = qobject_cast<OBSBasic*>(parent());
  108. if (!main)
  109. return;
  110. QString text;
  111. text += QString("CPU: ") +
  112. QString::number(main->GetCPUUsage(), 'f', 1) + QString("%");
  113. cpuUsage->setText(text);
  114. cpuUsage->setMinimumWidth(cpuUsage->width());
  115. }
  116. void OBSBasicStatusBar::UpdateSessionTime()
  117. {
  118. totalSeconds++;
  119. int seconds = totalSeconds % 60;
  120. int totalMinutes = totalSeconds / 60;
  121. int minutes = totalMinutes % 60;
  122. int hours = totalMinutes / 60;
  123. QString text;
  124. text.sprintf("%02d:%02d:%02d", hours, minutes, seconds);
  125. sessionTime->setText(text);
  126. sessionTime->setMinimumWidth(sessionTime->width());
  127. if (reconnectTimeout > 0) {
  128. QString msg = QTStr("Basic.StatusBar.Reconnecting");
  129. showMessage(msg.arg(QString::number(retries),
  130. QString::number(reconnectTimeout)));
  131. reconnectTimeout--;
  132. } else if (retries > 0) {
  133. QString msg = QTStr("Basic.StatusBar.AttemptingReconnect");
  134. showMessage(msg.arg(QString::number(retries)));
  135. }
  136. if (delaySecStopping > 0 || delaySecStarting > 0) {
  137. if (delaySecStopping > 0)
  138. --delaySecStopping;
  139. if (delaySecStarting > 0)
  140. --delaySecStarting;
  141. UpdateDelayMsg();
  142. }
  143. }
  144. void OBSBasicStatusBar::UpdateDroppedFrames()
  145. {
  146. if (!streamOutput)
  147. return;
  148. int totalDropped = obs_output_get_frames_dropped(streamOutput);
  149. int totalFrames = obs_output_get_total_frames(streamOutput);
  150. double percent = (double)totalDropped / (double)totalFrames * 100.0;
  151. if (!totalFrames)
  152. return;
  153. QString text = QTStr("DroppedFrames");
  154. text = text.arg(QString::number(totalDropped),
  155. QString::number(percent, 'f', 1));
  156. droppedFrames->setText(text);
  157. droppedFrames->setMinimumWidth(droppedFrames->width());
  158. }
  159. void OBSBasicStatusBar::OBSOutputReconnect(void *data, calldata_t *params)
  160. {
  161. OBSBasicStatusBar *statusBar =
  162. reinterpret_cast<OBSBasicStatusBar*>(data);
  163. int seconds = (int)calldata_int(params, "timeout_sec");
  164. QMetaObject::invokeMethod(statusBar, "Reconnect", Q_ARG(int, seconds));
  165. UNUSED_PARAMETER(params);
  166. }
  167. void OBSBasicStatusBar::OBSOutputReconnectSuccess(void *data, calldata_t *params)
  168. {
  169. OBSBasicStatusBar *statusBar =
  170. reinterpret_cast<OBSBasicStatusBar*>(data);
  171. QMetaObject::invokeMethod(statusBar, "ReconnectSuccess");
  172. UNUSED_PARAMETER(params);
  173. }
  174. void OBSBasicStatusBar::Reconnect(int seconds)
  175. {
  176. retries++;
  177. reconnectTimeout = seconds;
  178. if (streamOutput) {
  179. delaySecTotal = obs_output_get_active_delay(streamOutput);
  180. UpdateDelayMsg();
  181. }
  182. }
  183. void OBSBasicStatusBar::ReconnectSuccess()
  184. {
  185. showMessage(QTStr("Basic.StatusBar.ReconnectSuccessful"), 4000);
  186. retries = 0;
  187. reconnectTimeout = 0;
  188. bitrateUpdateSeconds = -1;
  189. lastBytesSent = 0;
  190. lastBytesSentTime = os_gettime_ns();
  191. if (streamOutput) {
  192. delaySecTotal = obs_output_get_active_delay(streamOutput);
  193. UpdateDelayMsg();
  194. }
  195. }
  196. void OBSBasicStatusBar::UpdateStatusBar()
  197. {
  198. UpdateBandwidth();
  199. UpdateSessionTime();
  200. UpdateDroppedFrames();
  201. }
  202. void OBSBasicStatusBar::StreamDelayStarting(int sec)
  203. {
  204. OBSBasic *main = qobject_cast<OBSBasic*>(parent());
  205. if (!main || !main->outputHandler)
  206. return;
  207. streamOutput = main->outputHandler->streamOutput;
  208. delaySecTotal = delaySecStarting = sec;
  209. UpdateDelayMsg();
  210. Activate();
  211. }
  212. void OBSBasicStatusBar::StreamDelayStopping(int sec)
  213. {
  214. delaySecTotal = delaySecStopping = sec;
  215. UpdateDelayMsg();
  216. }
  217. void OBSBasicStatusBar::StreamStarted(obs_output_t *output)
  218. {
  219. streamOutput = output;
  220. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  221. "reconnect", OBSOutputReconnect, this);
  222. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  223. "reconnect_success", OBSOutputReconnectSuccess, this);
  224. retries = 0;
  225. lastBytesSent = 0;
  226. lastBytesSentTime = os_gettime_ns();
  227. Activate();
  228. }
  229. void OBSBasicStatusBar::StreamStopped()
  230. {
  231. if (streamOutput) {
  232. signal_handler_disconnect(
  233. obs_output_get_signal_handler(streamOutput),
  234. "reconnect", OBSOutputReconnect, this);
  235. signal_handler_disconnect(
  236. obs_output_get_signal_handler(streamOutput),
  237. "reconnect_success", OBSOutputReconnectSuccess,
  238. this);
  239. streamOutput = nullptr;
  240. clearMessage();
  241. Deactivate();
  242. }
  243. }
  244. void OBSBasicStatusBar::RecordingStarted(obs_output_t *output)
  245. {
  246. recordOutput = output;
  247. Activate();
  248. }
  249. void OBSBasicStatusBar::RecordingStopped()
  250. {
  251. recordOutput = nullptr;
  252. Deactivate();
  253. }