]> git.sesse.net Git - nageru/blob - nageru/main.cpp
Fix a dangling reference (found by GCC 14).
[nageru] / nageru / main.cpp
1 extern "C" {
2 #include <libavformat/version.h>
3 #include <libavutil/version.h>
4 }
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/mman.h>
9 #include <epoxy/gl.h>  // IWYU pragma: keep
10 #include <QApplication>
11 #include <QCoreApplication>
12 #include <QGL>
13 #include <QSize>
14 #include <QSurfaceFormat>
15 #include <string>
16
17 #ifdef HAVE_CEF
18 #include <cef_app.h>
19 #endif
20
21 #ifdef HAVE_SRT
22 #include <srt/srt.h>
23 #endif
24
25 #include "basic_stats.h"
26 #ifdef HAVE_CEF
27 #include "nageru_cef_app.h"
28 #endif
29 #include "shared/context.h"
30 #include "flags.h"
31 #include "mainwindow.h"
32 #include "mixer.h"
33 #include "quicksync_encoder.h"
34
35 #ifdef HAVE_CEF
36 CefRefPtr<NageruCefApp> cef_app;
37 #endif
38
39 int main(int argc, char *argv[])
40 {
41 #ifdef HAVE_CEF
42         // Let CEF have first priority on parsing the command line, because we might be
43         // launched as a CEF sub-process.
44         CefMainArgs main_args(argc, argv);
45         cef_app = CefRefPtr<NageruCefApp>(new NageruCefApp());
46         int err = CefExecuteProcess(main_args, cef_app.get(), nullptr);
47         if (err >= 0) {
48                 return err;
49         }
50
51         // CEF wants to use GLib for its main loop, which interferes with Qt's use of it.
52         // The alternative is trying to integrate CEF into Qt's main loop, but that requires
53         // fairly extensive cross-thread communication and that parts of CEF runs on Qt's UI
54         // thread.
55         setenv("QT_NO_GLIB", "1", 0);
56 #endif
57
58         parse_flags(PROGRAM_NAGERU, argc, argv);
59
60         if (global_flags.va_display.empty() && !global_flags.x264_video_to_disk) {
61                 // The user didn't specify a VA-API display, but we need one.
62                 // See if the default works, and if not, let's try to help
63                 // the user by seeing if there's any that would work automatically.
64                 global_flags.va_display = QuickSyncEncoder::get_usable_va_display();
65         }
66
67         // The OpenGL widgets do not work well with the native Wayland integration.
68         setenv("QT_QPA_PLATFORM", "xcb", 0);
69
70         if ((global_flags.va_display.empty() ||
71              global_flags.va_display[0] != '/') && !global_flags.x264_video_to_disk) {
72                 // We normally use EGL for zerocopy, but if we use VA against DRM
73                 // instead of against X11, we turn it off, and then don't need EGL.
74                 setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0);
75         }
76         setlinebuf(stdout);
77 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
78         av_register_all();
79 #endif
80
81 #ifdef HAVE_SRT
82         if (global_flags.srt_port >= 0 || !global_flags.srt_destination_host.empty()) {
83                 srt_startup();
84         }
85 #endif
86
87         QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
88
89         QSurfaceFormat fmt;
90         fmt.setDepthBufferSize(0);
91         fmt.setStencilBufferSize(0);
92         fmt.setProfile(QSurfaceFormat::CoreProfile);
93         fmt.setMajorVersion(3);
94         fmt.setMinorVersion(1);
95
96         // Turn off vsync, since Qt generally gives us at most frame rate
97         // (display frequency) / (number of QGLWidgets active).
98         fmt.setSwapInterval(0);
99
100         QSurfaceFormat::setDefaultFormat(fmt);
101
102         QGLFormat::setDefaultFormat(QGLFormat::fromSurfaceFormat(fmt));
103
104         QApplication app(argc, argv);
105         global_share_widget = new QGLWidget();
106         if (!global_share_widget->isValid()) {
107                 fprintf(stderr, "Failed to initialize OpenGL. Nageru needs at least OpenGL 3.1 to function properly.\n");
108                 abort();
109         }
110
111         MainWindow mainWindow;
112         mainWindow.resize(QSize(1500, 910));
113         mainWindow.show();
114
115         app.installEventFilter(&mainWindow);  // For white balance color picking.
116
117         // Even on an otherwise unloaded system, it would seem writing the recording
118         // to disk (potentially terabytes of data as time goes by) causes Nageru
119         // to be pushed out of RAM. If we have the right privileges, simply lock us
120         // into memory for better realtime behavior.
121         if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
122                 perror("mlockall()");
123                 fprintf(stderr, "Failed to lock Nageru into RAM. You probably want to\n");
124                 fprintf(stderr, "increase \"memlock\" for your user in limits.conf\n");
125                 fprintf(stderr, "for better realtime behavior.\n");
126                 uses_mlock = false;
127         } else {
128                 uses_mlock = true;
129         }
130
131         int rc = app.exec();
132         delete global_mixer;
133 #ifdef HAVE_SRT
134         if (global_flags.srt_port >= 0) {
135                 srt_cleanup();
136         }
137 #endif
138         return rc;
139 }