Sunshine v2026.319.132152
Self-hosted game stream host for Moonlight.
video.h
Go to the documentation of this file.
1
5#pragma once
6
7// local includes
8#include "input.h"
9#include "platform/common.h"
10#include "thread_safe.h"
11#include "video_colorspace.h"
12
13extern "C" {
14#include <libavcodec/avcodec.h>
15#include <libswscale/swscale.h>
16}
17
18struct AVPacket;
19
20namespace video {
21
22 /* Encoding configuration requested by remote client */
23 struct config_t {
24 int width; // Video width in pixels
25 int height; // Video height in pixels
26 int framerate; // Requested framerate, used in individual frame bitrate budget calculation
27 int framerateX100; // Optional field for streaming at NTSC or similar rates e.g. 59.94 = 5994
28 int bitrate; // Video bitrate in kilobits (1000 bits) for requested framerate
29 int slicesPerFrame; // Number of slices per frame
30 int numRefFrames; // Max number of reference frames
31
32 /* Requested color range and SDR encoding colorspace, HDR encoding colorspace is always BT.2020+ST2084
33 Color range (encoderCscMode & 0x1) : 0 - limited, 1 - full
34 SDR encoding colorspace (encoderCscMode >> 1) : 0 - BT.601, 1 - BT.709, 2 - BT.2020 */
35 int encoderCscMode;
36
37 int videoFormat; // 0 - H.264, 1 - HEVC, 2 - AV1
38
39 /* Encoding color depth (bit depth): 0 - 8-bit, 1 - 10-bit
40 HDR encoding activates when color depth is higher than 8-bit and the display which is being captured is operating in HDR mode */
41 int dynamicRange;
42
43 int chromaSamplingType; // 0 - 4:2:0, 1 - 4:4:4
44
45 int enableIntraRefresh; // 0 - disabled, 1 - enabled
46 };
47
48 platf::mem_type_e map_base_dev_type(AVHWDeviceType type);
49 platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt);
50
51 void free_ctx(AVCodecContext *ctx);
52 void free_frame(AVFrame *frame);
53 void free_buffer(AVBufferRef *ref);
54
59 using img_event_t = std::shared_ptr<safe::event_t<std::shared_ptr<platf::img_t>>>;
60
62 virtual ~encoder_platform_formats_t() = default;
63 platf::mem_type_e dev_type;
64 platf::pix_fmt_e pix_fmt_8bit;
65 platf::pix_fmt_e pix_fmt_10bit;
66 platf::pix_fmt_e pix_fmt_yuv444_8bit;
67 platf::pix_fmt_e pix_fmt_yuv444_10bit;
68 };
69
71 using init_buffer_function_t = std::function<util::Either<avcodec_buffer_t, int>(platf::avcodec_encode_device_t *)>;
72
74 const AVHWDeviceType &avcodec_base_dev_type,
75 const AVHWDeviceType &avcodec_derived_dev_type,
76 const AVPixelFormat &avcodec_dev_pix_fmt,
77 const AVPixelFormat &avcodec_pix_fmt_8bit,
78 const AVPixelFormat &avcodec_pix_fmt_10bit,
79 const AVPixelFormat &avcodec_pix_fmt_yuv444_8bit,
80 const AVPixelFormat &avcodec_pix_fmt_yuv444_10bit,
81 const init_buffer_function_t &init_avcodec_hardware_input_buffer_function
82 ):
83 avcodec_base_dev_type {avcodec_base_dev_type},
84 avcodec_derived_dev_type {avcodec_derived_dev_type},
85 avcodec_dev_pix_fmt {avcodec_dev_pix_fmt},
86 avcodec_pix_fmt_8bit {avcodec_pix_fmt_8bit},
87 avcodec_pix_fmt_10bit {avcodec_pix_fmt_10bit},
88 avcodec_pix_fmt_yuv444_8bit {avcodec_pix_fmt_yuv444_8bit},
89 avcodec_pix_fmt_yuv444_10bit {avcodec_pix_fmt_yuv444_10bit},
90 init_avcodec_hardware_input_buffer {init_avcodec_hardware_input_buffer_function} {
91 dev_type = map_base_dev_type(avcodec_base_dev_type);
92 pix_fmt_8bit = map_pix_fmt(avcodec_pix_fmt_8bit);
93 pix_fmt_10bit = map_pix_fmt(avcodec_pix_fmt_10bit);
94 pix_fmt_yuv444_8bit = map_pix_fmt(avcodec_pix_fmt_yuv444_8bit);
95 pix_fmt_yuv444_10bit = map_pix_fmt(avcodec_pix_fmt_yuv444_10bit);
96 }
97
98 AVHWDeviceType avcodec_base_dev_type;
99 AVHWDeviceType avcodec_derived_dev_type;
100 AVPixelFormat avcodec_dev_pix_fmt;
101 AVPixelFormat avcodec_pix_fmt_8bit;
102 AVPixelFormat avcodec_pix_fmt_10bit;
103 AVPixelFormat avcodec_pix_fmt_yuv444_8bit;
104 AVPixelFormat avcodec_pix_fmt_yuv444_10bit;
105
106 init_buffer_function_t init_avcodec_hardware_input_buffer;
107 };
108
111 const platf::mem_type_e &dev_type,
112 const platf::pix_fmt_e &pix_fmt_8bit,
113 const platf::pix_fmt_e &pix_fmt_10bit,
114 const platf::pix_fmt_e &pix_fmt_yuv444_8bit,
115 const platf::pix_fmt_e &pix_fmt_yuv444_10bit
116 ) {
117 encoder_platform_formats_t::dev_type = dev_type;
118 encoder_platform_formats_t::pix_fmt_8bit = pix_fmt_8bit;
119 encoder_platform_formats_t::pix_fmt_10bit = pix_fmt_10bit;
120 encoder_platform_formats_t::pix_fmt_yuv444_8bit = pix_fmt_yuv444_8bit;
121 encoder_platform_formats_t::pix_fmt_yuv444_10bit = pix_fmt_yuv444_10bit;
122 }
123 };
124
125 struct encoder_t {
126 std::string_view name;
127
136
137 static std::string_view from_flag(flag_e flag) {
138#define _CONVERT(x) \
139 case flag_e::x: \
140 return std::string_view(#x)
141 switch (flag) {
142 _CONVERT(PASSED);
143 _CONVERT(REF_FRAMES_RESTRICT);
144 _CONVERT(DYNAMIC_RANGE);
145 _CONVERT(YUV444);
146 _CONVERT(VUI_PARAMETERS);
147 _CONVERT(MAX_FLAGS);
148 }
149#undef _CONVERT
150
151 return {"unknown"};
152 }
153
154 struct option_t {
155 KITTY_DEFAULT_CONSTR_MOVE(option_t)
156 option_t(const option_t &) = default;
157
158 std::string name;
159 std::variant<int, int *, std::optional<int> *, std::function<int()>, std::string, std::string *, std::function<const std::string(const config_t &)>> value;
160
161 option_t(std::string &&name, decltype(value) &&value):
162 name {std::move(name)},
163 value {std::move(value)} {
164 }
165 };
166
167 const std::unique_ptr<const encoder_platform_formats_t> platform_formats;
168
169 struct codec_t {
170 std::vector<option_t> common_options;
171 std::vector<option_t> sdr_options;
172 std::vector<option_t> hdr_options;
173 std::vector<option_t> sdr444_options;
174 std::vector<option_t> hdr444_options;
175 std::vector<option_t> fallback_options;
176
177 std::string name;
178 std::bitset<MAX_FLAGS> capabilities;
179
180 bool operator[](flag_e flag) const {
181 return capabilities[(std::size_t) flag];
182 }
183
184 std::bitset<MAX_FLAGS>::reference operator[](flag_e flag) {
185 return capabilities[(std::size_t) flag];
186 }
187 };
188
189 codec_t av1;
190 codec_t hevc;
191 codec_t h264;
192
193 const codec_t &codec_from_config(const config_t &config) const {
194 switch (config.videoFormat) {
195 default:
196 BOOST_LOG(error) << "Unknown video format " << config.videoFormat << ", falling back to H.264";
197 // fallthrough
198 case 0:
199 return h264;
200 case 1:
201 return hevc;
202 case 2:
203 return av1;
204 }
205 }
206
207 uint32_t flags;
208 };
209
211 virtual ~encode_session_t() = default;
212
213 virtual int convert(platf::img_t &img) = 0;
214
215 virtual void request_idr_frame() = 0;
216
217 virtual void request_normal_frame() = 0;
218
219 virtual void invalidate_ref_frames(int64_t first_frame, int64_t last_frame) = 0;
220 };
221
222 // encoders
223 extern encoder_t software;
224
225#if !defined(__APPLE__)
226 extern encoder_t nvenc; // available for windows and linux
227#endif
228
229#ifdef _WIN32
230 extern encoder_t amdvce;
231 extern encoder_t quicksync;
232 extern encoder_t mediafoundation;
233#endif
234
235#if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__)
236 extern encoder_t vaapi;
237#endif
238
239#ifdef __APPLE__
240 extern encoder_t videotoolbox;
241#endif
242
244 virtual ~packet_raw_t() = default;
245
246 virtual bool is_idr() = 0;
247
248 virtual int64_t frame_index() = 0;
249
250 virtual uint8_t *data() = 0;
251
252 virtual size_t data_size() = 0;
253
254 struct replace_t {
255 std::string_view old;
256 std::string_view _new;
257
258 KITTY_DEFAULT_CONSTR_MOVE(replace_t)
259
260 replace_t(std::string_view old, std::string_view _new) noexcept:
261 old {std::move(old)},
262 _new {std::move(_new)} {
263 }
264 };
265
266 std::vector<replace_t> *replacements = nullptr;
267 void *channel_data = nullptr;
268 bool after_ref_frame_invalidation = false;
269 std::optional<std::chrono::steady_clock::time_point> frame_timestamp;
270 };
271
274 av_packet = av_packet_alloc();
275 }
276
278 av_packet_free(&this->av_packet);
279 }
280
281 bool is_idr() override {
282 return av_packet->flags & AV_PKT_FLAG_KEY;
283 }
284
285 int64_t frame_index() override {
286 return av_packet->pts;
287 }
288
289 uint8_t *data() override {
290 return av_packet->data;
291 }
292
293 size_t data_size() override {
294 return av_packet->size;
295 }
296
297 AVPacket *av_packet;
298 };
299
301 packet_raw_generic(std::vector<uint8_t> &&frame_data, int64_t frame_index, bool idr):
302 frame_data {std::move(frame_data)},
303 index {frame_index},
304 idr {idr} {
305 }
306
307 bool is_idr() override {
308 return idr;
309 }
310
311 int64_t frame_index() override {
312 return index;
313 }
314
315 uint8_t *data() override {
316 return frame_data.data();
317 }
318
319 size_t data_size() override {
320 return frame_data.size();
321 }
322
323 std::vector<uint8_t> frame_data;
324 int64_t index;
325 bool idr;
326 };
327
328 using packet_t = std::unique_ptr<packet_raw_t>;
329
331 explicit hdr_info_raw_t(bool enabled):
332 enabled {enabled},
333 metadata {} {};
334 explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata):
335 enabled {enabled},
336 metadata {metadata} {};
337
338 bool enabled;
339 SS_HDR_METADATA metadata;
340 };
341
342 using hdr_info_t = std::unique_ptr<hdr_info_raw_t>;
343
344 extern int active_hevc_mode;
345 extern int active_av1_mode;
346 extern bool last_encoder_probe_supported_ref_frames_invalidation;
347 extern std::array<bool, 3> last_encoder_probe_supported_yuv444_for_codec; // 0 - H.264, 1 - HEVC, 2 - AV1
348
349 void capture(
350 safe::mail_t mail,
351 config_t config,
352 void *channel_data
353 );
354
355 bool validate_encoder(encoder_t &encoder, bool expect_failure);
356
365 int probe_encoders();
366
367 // Several NTSC standard refresh rates are hardcoded here, because their
368 // true rate requires a denominator of 1001. ffmpeg's av_d2q() would assume it could
369 // reduce 29.97 to 2997/100 but this would be slightly wrong. We also include
370 // support for 23.976 film in case someone wants to stream a film at the perfect
371 // framerate.
372 inline AVRational framerateX100_to_rational(const int framerateX100) {
373 if (framerateX100 % 2997 == 0) {
374 // Multiples of NTSC 29.97 e.g. 59.94, 119.88
375 return AVRational {(framerateX100 / 2997) * 30000, 1001};
376 }
377 switch (framerateX100) {
378 case 2397: // the other weird NTSC framerate, assume these want 23.976 film
379 case 2398:
380 return AVRational {24000, 1001};
381 default:
382 // any other fractional rate can be reduced by ffmpeg. Max is set to 1 << 26 based on docs:
383 // "rational numbers with |num| <= 1<<26 && |den| <= 1<<26 can be recovered exactly from their double representation"
384 return av_d2q((double) framerateX100 / 100.0f, 1 << 26);
385 }
386 }
387} // namespace video
Definition utility.h:530
Declarations for common platform specific utilities.
mem_type_e
Definition common.h:229
pix_fmt_e
Definition common.h:238
Declarations for gamepad, keyboard, and mouse input handling.
Handles process-wide communication.
Definition globals.h:34
Standalone NVENC encoder.
Definition nvenc_base.cpp:90
Definition common.h:412
Definition common.h:369
Definition video.h:23
Definition video.h:210
Definition video.h:169
Definition video.h:154
Definition video.h:125
flag_e
Definition video.h:128
@ DYNAMIC_RANGE
HDR support.
Definition video.h:131
@ VUI_PARAMETERS
AMD encoder with VAAPI doesn't add VUI parameters to SPS.
Definition video.h:133
@ PASSED
Indicates the encoder is supported.
Definition video.h:129
@ REF_FRAMES_RESTRICT
Set maximum reference frames.
Definition video.h:130
@ YUV444
YUV 4:4:4 support.
Definition video.h:132
@ MAX_FLAGS
Maximum number of flags.
Definition video.h:134
Definition video.h:330
Definition video.h:272
Definition video.h:300
Definition video.h:254
Definition video.h:243
Declarations for thread-safe data structures.
flag_e
Definition video.cpp:290
int probe_encoders()
Probe encoders and select the preferred encoder. This is called once at startup and each time a strea...
Definition video.cpp:2721
Declarations for colorspace functions.