window-basic-status-bar.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. reconnectTimeout = 0;
  58. active = false;
  59. }
  60. }
  61. void OBSBasicStatusBar::UpdateDelayMsg()
  62. {
  63. QString msg;
  64. if (delaySecTotal) {
  65. if (delaySecStarting && !delaySecStopping) {
  66. msg = QTStr("Basic.StatusBar.DelayStartingIn");
  67. msg = msg.arg(QString::number(delaySecStarting));
  68. } else if (!delaySecStarting && delaySecStopping) {
  69. msg = QTStr("Basic.StatusBar.DelayStoppingIn");
  70. msg = msg.arg(QString::number(delaySecStopping));
  71. } else if (delaySecStarting && delaySecStopping) {
  72. msg = QTStr("Basic.StatusBar.DelayStartingStoppingIn");
  73. msg = msg.arg(QString::number(delaySecStopping),
  74. QString::number(delaySecStarting));
  75. } else {
  76. msg = QTStr("Basic.StatusBar.Delay");
  77. msg = msg.arg(QString::number(delaySecTotal));
  78. }
  79. }
  80. delayInfo->setText(msg);
  81. }
  82. #define BITRATE_UPDATE_SECONDS 2
  83. void OBSBasicStatusBar::UpdateBandwidth()
  84. {
  85. if (!streamOutput)
  86. return;
  87. if (++bitrateUpdateSeconds < BITRATE_UPDATE_SECONDS)
  88. return;
  89. uint64_t bytesSent = obs_output_get_total_bytes(streamOutput);
  90. uint64_t bytesSentTime = os_gettime_ns();
  91. if (bytesSent == 0)
  92. lastBytesSent = 0;
  93. uint64_t bitsBetween = (bytesSent - lastBytesSent) * 8;
  94. double timePassed = double(bytesSentTime - lastBytesSentTime) /
  95. 1000000000.0;
  96. double kbitsPerSec = double(bitsBetween) / timePassed / 1000.0;
  97. QString text;
  98. text += QString("kb/s: ") +
  99. QString::number(kbitsPerSec, 'f', 0);
  100. kbps->setText(text);
  101. kbps->setMinimumWidth(kbps->width());
  102. lastBytesSent = bytesSent;
  103. lastBytesSentTime = bytesSentTime;
  104. bitrateUpdateSeconds = 0;
  105. }
  106. void OBSBasicStatusBar::UpdateCPUUsage()
  107. {
  108. OBSBasic *main = qobject_cast<OBSBasic*>(parent());
  109. if (!main)
  110. return;
  111. QString text;
  112. text += QString("CPU: ") +
  113. QString::number(main->GetCPUUsage(), 'f', 1) + QString("%");
  114. cpuUsage->setText(text);
  115. cpuUsage->setMinimumWidth(cpuUsage->width());
  116. }
  117. void OBSBasicStatusBar::UpdateSessionTime()
  118. {
  119. totalSeconds++;
  120. int seconds = totalSeconds % 60;
  121. int totalMinutes = totalSeconds / 60;
  122. int minutes = totalMinutes % 60;
  123. int hours = totalMinutes / 60;
  124. QString text;
  125. text.sprintf("%02d:%02d:%02d", hours, minutes, seconds);
  126. sessionTime->setText(text);
  127. sessionTime->setMinimumWidth(sessionTime->width());
  128. if (reconnectTimeout > 0) {
  129. QString msg = QTStr("Basic.StatusBar.Reconnecting");
  130. showMessage(msg.arg(QString::number(retries),
  131. QString::number(reconnectTimeout)));
  132. reconnectTimeout--;
  133. } else if (retries > 0) {
  134. QString msg = QTStr("Basic.StatusBar.AttemptingReconnect");
  135. showMessage(msg.arg(QString::number(retries)));
  136. }
  137. if (delaySecStopping > 0 || delaySecStarting > 0) {
  138. if (delaySecStopping > 0)
  139. --delaySecStopping;
  140. if (delaySecStarting > 0)
  141. --delaySecStarting;
  142. UpdateDelayMsg();
  143. }
  144. }
  145. void OBSBasicStatusBar::UpdateDroppedFrames()
  146. {
  147. if (!streamOutput)
  148. return;
  149. int totalDropped = obs_output_get_frames_dropped(streamOutput);
  150. int totalFrames = obs_output_get_total_frames(streamOutput);
  151. double percent = (double)totalDropped / (double)totalFrames * 100.0;
  152. if (!totalFrames)
  153. return;
  154. QString text = QTStr("DroppedFrames");
  155. text = text.arg(QString::number(totalDropped),
  156. QString::number(percent, 'f', 1));
  157. droppedFrames->setText(text);
  158. droppedFrames->setMinimumWidth(droppedFrames->width());
  159. }
  160. void OBSBasicStatusBar::OBSOutputReconnect(void *data, calldata_t *params)
  161. {
  162. OBSBasicStatusBar *statusBar =
  163. reinterpret_cast<OBSBasicStatusBar*>(data);
  164. int seconds = (int)calldata_int(params, "timeout_sec");
  165. QMetaObject::invokeMethod(statusBar, "Reconnect", Q_ARG(int, seconds));
  166. UNUSED_PARAMETER(params);
  167. }
  168. void OBSBasicStatusBar::OBSOutputReconnectSuccess(void *data, calldata_t *params)
  169. {
  170. OBSBasicStatusBar *statusBar =
  171. reinterpret_cast<OBSBasicStatusBar*>(data);
  172. QMetaObject::invokeMethod(statusBar, "ReconnectSuccess");
  173. UNUSED_PARAMETER(params);
  174. }
  175. void OBSBasicStatusBar::Reconnect(int seconds)
  176. {
  177. retries++;
  178. reconnectTimeout = seconds;
  179. if (streamOutput) {
  180. delaySecTotal = obs_output_get_active_delay(streamOutput);
  181. UpdateDelayMsg();
  182. }
  183. }
  184. void OBSBasicStatusBar::ReconnectSuccess()
  185. {
  186. showMessage(QTStr("Basic.StatusBar.ReconnectSuccessful"), 4000);
  187. retries = 0;
  188. reconnectTimeout = 0;
  189. bitrateUpdateSeconds = -1;
  190. lastBytesSent = 0;
  191. lastBytesSentTime = os_gettime_ns();
  192. if (streamOutput) {
  193. delaySecTotal = obs_output_get_active_delay(streamOutput);
  194. UpdateDelayMsg();
  195. }
  196. }
  197. void OBSBasicStatusBar::UpdateStatusBar()
  198. {
  199. UpdateBandwidth();
  200. UpdateSessionTime();
  201. UpdateDroppedFrames();
  202. }
  203. void OBSBasicStatusBar::StreamDelayStarting(int sec)
  204. {
  205. OBSBasic *main = qobject_cast<OBSBasic*>(parent());
  206. if (!main || !main->outputHandler)
  207. return;
  208. streamOutput = main->outputHandler->streamOutput;
  209. delaySecTotal = delaySecStarting = sec;
  210. UpdateDelayMsg();
  211. Activate();
  212. }
  213. void OBSBasicStatusBar::StreamDelayStopping(int sec)
  214. {
  215. delaySecTotal = delaySecStopping = sec;
  216. UpdateDelayMsg();
  217. }
  218. void OBSBasicStatusBar::StreamStarted(obs_output_t *output)
  219. {
  220. streamOutput = output;
  221. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  222. "reconnect", OBSOutputReconnect, this);
  223. signal_handler_connect(obs_output_get_signal_handler(streamOutput),
  224. "reconnect_success", OBSOutputReconnectSuccess, this);
  225. retries = 0;
  226. lastBytesSent = 0;
  227. lastBytesSentTime = os_gettime_ns();
  228. Activate();
  229. }
  230. void OBSBasicStatusBar::StreamStopped()
  231. {
  232. if (streamOutput) {
  233. signal_handler_disconnect(
  234. obs_output_get_signal_handler(streamOutput),
  235. "reconnect", OBSOutputReconnect, this);
  236. signal_handler_disconnect(
  237. obs_output_get_signal_handler(streamOutput),
  238. "reconnect_success", OBSOutputReconnectSuccess,
  239. this);
  240. streamOutput = nullptr;
  241. clearMessage();
  242. Deactivate();
  243. }
  244. }
  245. void OBSBasicStatusBar::RecordingStarted(obs_output_t *output)
  246. {
  247. recordOutput = output;
  248. Activate();
  249. }
  250. void OBSBasicStatusBar::RecordingStopped()
  251. {
  252. recordOutput = nullptr;
  253. Deactivate();
  254. }