enum LongOption {
OPTION_HELP = 1000,
OPTION_SLOW_DOWN_INPUT = 1001,
- OPTION_HTTP_PORT = 1002
+ OPTION_HTTP_PORT = 1002,
+ OPTION_TALLY_URL = 1003
};
void usage()
fprintf(stderr, " 4 = best (not realtime on any current GPU)\n");
fprintf(stderr, " -d, --working-directory DIR where to store frames and database\n");
fprintf(stderr, " --http-port PORT which port to listen on for output\n");
+ fprintf(stderr, " --tally-url URL URL to get tally color from (polled every 100 ms)\n");
}
void parse_flags(int argc, char * const argv[])
{ "interpolation-quality", required_argument, 0, 'q' },
{ "working-directory", required_argument, 0, 'd' },
{ "http-port", required_argument, 0, OPTION_HTTP_PORT },
+ { "tally-url", required_argument, 0, OPTION_TALLY_URL },
{ 0, 0, 0, 0 }
};
for ( ;; ) {
case OPTION_HTTP_PORT:
global_flags.http_port = atoi(optarg);
break;
+ case OPTION_TALLY_URL:
+ global_flags.tally_url = optarg;
+ break;
case OPTION_HELP:
usage();
exit(0);
bool interpolation_quality_set = false;
uint16_t http_port = DEFAULT_HTTPD_PORT;
double output_framerate = 60000.0 / 1001.0;
+ std::string tally_url;
};
extern Flags global_flags;
#include <QFileDialog>
#include <QMessageBox>
#include <QMouseEvent>
+#include <QNetworkReply>
#include <QShortcut>
#include <QTimer>
#include <QWheelEvent>
}
}
change_num_cameras();
+
+ if (!global_flags.tally_url.empty()) {
+ start_tally();
+ }
}
void MainWindow::change_num_cameras()
*model = new_model;
connect(new_model, &Model::any_content_changed, this, &MainWindow::content_changed);
}
+
+void MainWindow::start_tally()
+{
+ http_reply = http.get(QNetworkRequest(QString::fromStdString(global_flags.tally_url)));
+ connect(http_reply, &QNetworkReply::finished, this, &MainWindow::tally_received);
+}
+
+void MainWindow::tally_received()
+{
+ unsigned time_to_next_tally_ms;
+ if (http_reply->error()) {
+ fprintf(stderr, "HTTP get of '%s' failed: %s\n", global_flags.tally_url.c_str(),
+ http_reply->errorString().toStdString().c_str());
+ ui->live_frame->setStyleSheet("");
+ time_to_next_tally_ms = 1000;
+ } else {
+ string contents = http_reply->readAll().toStdString();
+ ui->live_frame->setStyleSheet(QString::fromStdString("background: " + contents));
+ time_to_next_tally_ms = 100;
+ }
+ http_reply->deleteLater();
+ http_reply = nullptr;
+
+ QTimer::singleShot(time_to_next_tally_ms, this, &MainWindow::start_tally);
+}
#include <mutex>
#include <QLabel>
#include <QMainWindow>
+#include <QNetworkAccessManager>
#include <stdbool.h>
#include <sys/types.h>
#include <string>
};
std::vector<FrameAndDisplay> displays;
+ // Used to get tally information, if a tally URL is set.
+ QNetworkAccessManager http;
+ QNetworkReply *http_reply = nullptr;
+
void change_num_cameras();
void cue_in_clicked();
void cue_out_clicked();
template <class Model>
void replace_model(QTableView *view, Model **model, Model *new_model);
+ void start_tally();
+ void tally_received();
+
private slots:
void relayout();
};
<layout class="QVBoxLayout" name="video_displays" stretch="1,2">
<item>
<layout class="QHBoxLayout" name="preview_and_live_panes">
+ <property name="spacing">
+ <number>3</number>
+ </property>
<item>
<layout class="QVBoxLayout" name="preview_pane" stretch="1,0">
<item>
- <widget class="JPEGFrameView" name="preview_display" native="true"/>
- </item>
- <item>
- <layout class="QHBoxLayout" name="preview_layout">
- <property name="spacing">
+ <widget class="QFrame" name="preview_frame">
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
<number>0</number>
</property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="JPEGFrameView" name="preview_display" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="preview_layout" stretch="0">
<item>
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="preview_label">
<property name="text">
<string>Preview output</string>
</property>
<item>
<layout class="QVBoxLayout" name="live_pane" stretch="1,0">
<item>
- <widget class="JPEGFrameView" name="live_display" native="true"/>
+ <widget class="QFrame" name="live_frame">
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="JPEGFrameView" name="live_display" native="true"/>
+ </item>
+ </layout>
+ </widget>
</item>
<item>
<widget class="QLabel" name="live_label">
movitdep = dependency('movit')
protobufdep = dependency('protobuf')
qcustomplotdep = cxx.find_library('qcustomplot')
-qt5deps = dependency('qt5', modules: ['Core', 'Gui', 'Widgets', 'OpenGLExtensions', 'OpenGL', 'PrintSupport'])
+qt5deps = dependency('qt5', modules: ['Core', 'Gui', 'Widgets', 'OpenGLExtensions', 'OpenGL', 'Network'])
sdl2_imagedep = dependency('SDL2_image')
sdl2dep = dependency('sdl2')
sqlite3dep = dependency('sqlite3')