2 #include <libavformat/avformat.h>
8 #include <epoxy/gl.h> // IWYU pragma: keep
9 #include <QApplication>
10 #include <QCoreApplication>
13 #include <QSurfaceFormat>
18 #include <cef_browser.h>
19 #include <cef_client.h>
20 #include <cef_version.h>
27 #include "basic_stats.h"
29 #include "nageru_cef_app.h"
31 #include "shared/context.h"
33 #include "image_input.h"
34 #include "mainwindow.h"
36 #include "quicksync_encoder.h"
39 CefRefPtr<NageruCefApp> cef_app;
42 int main(int argc, char *argv[])
45 // Let CEF have first priority on parsing the command line, because we might be
46 // launched as a CEF sub-process.
47 CefMainArgs main_args(argc, argv);
48 cef_app = CefRefPtr<NageruCefApp>(new NageruCefApp());
49 int err = CefExecuteProcess(main_args, cef_app.get(), nullptr);
54 // CEF wants to use GLib for its main loop, which interferes with Qt's use of it.
55 // The alternative is trying to integrate CEF into Qt's main loop, but that requires
56 // fairly extensive cross-thread communication and that parts of CEF runs on Qt's UI
58 setenv("QT_NO_GLIB", "1", 0);
61 parse_flags(PROGRAM_NAGERU, argc, argv);
63 if (global_flags.va_display.empty() && !global_flags.x264_video_to_disk) {
64 // The user didn't specify a VA-API display, but we need one.
65 // See if the default works, and if not, let's try to help
66 // the user by seeing if there's any that would work automatically.
67 global_flags.va_display = QuickSyncEncoder::get_usable_va_display();
70 // The OpenGL widgets do not work well with the native Wayland integration.
71 setenv("QT_QPA_PLATFORM", "xcb", 0);
73 if ((global_flags.va_display.empty() ||
74 global_flags.va_display[0] != '/') && !global_flags.x264_video_to_disk) {
75 // We normally use EGL for zerocopy, but if we use VA against DRM
76 // instead of against X11, we turn it off, and then don't need EGL.
77 setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0);
80 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
85 if (global_flags.srt_port >= 0 || !global_flags.srt_destination_host.empty()) {
90 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
93 fmt.setDepthBufferSize(0);
94 fmt.setStencilBufferSize(0);
95 fmt.setProfile(QSurfaceFormat::CoreProfile);
96 fmt.setMajorVersion(3);
97 fmt.setMinorVersion(1);
99 // Turn off vsync, since Qt generally gives us at most frame rate
100 // (display frequency) / (number of QGLWidgets active).
101 fmt.setSwapInterval(0);
103 QSurfaceFormat::setDefaultFormat(fmt);
105 QGLFormat::setDefaultFormat(QGLFormat::fromSurfaceFormat(fmt));
107 QApplication app(argc, argv);
108 global_share_widget = new QGLWidget();
109 if (!global_share_widget->isValid()) {
110 fprintf(stderr, "Failed to initialize OpenGL. Nageru needs at least OpenGL 3.1 to function properly.\n");
114 MainWindow mainWindow;
115 mainWindow.resize(QSize(1500, 910));
118 app.installEventFilter(&mainWindow); // For white balance color picking.
120 // Even on an otherwise unloaded system, it would seem writing the recording
121 // to disk (potentially terabytes of data as time goes by) causes Nageru
122 // to be pushed out of RAM. If we have the right privileges, simply lock us
123 // into memory for better realtime behavior.
124 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
125 perror("mlockall()");
126 fprintf(stderr, "Failed to lock Nageru into RAM. You probably want to\n");
127 fprintf(stderr, "increase \"memlock\" for your user in limits.conf\n");
128 fprintf(stderr, "for better realtime behavior.\n");
137 if (global_flags.srt_port >= 0) {