From 9c609b5fc13aef6c7f8f7ee275b7dd7a2b6fdf7c Mon Sep 17 00:00:00 2001 From: El Date: Thu, 23 Oct 2025 18:07:46 +0000 Subject: [PATCH] Refactor --- common/rfb/ConnParams.cxx | 169 ++++----- common/rfb/ConnParams.h | 19 +- common/rfb/EncodeManager.cxx | 55 ++- common/rfb/EncodeManager.h | 1 + common/rfb/Encoder.h | 2 +- common/rfb/HextileEncoder.cxx | 6 +- common/rfb/HextileEncoder.h | 18 +- common/rfb/RREEncoder.cxx | 6 +- common/rfb/RREEncoder.h | 10 +- common/rfb/RawEncoder.cxx | 6 +- common/rfb/RawEncoder.h | 10 +- common/rfb/SMsgHandler.h | 1 + common/rfb/SMsgReader.cxx | 15 +- common/rfb/SMsgReader.h | 1 + common/rfb/SMsgWriter.cxx | 20 + common/rfb/SMsgWriter.h | 1 + common/rfb/TightEncoder.cxx | 6 +- common/rfb/TightEncoder.h | 12 +- common/rfb/TightJPEGEncoder.cxx | 6 +- common/rfb/TightJPEGEncoder.h | 16 +- common/rfb/TightQOIEncoder.cxx | 6 +- common/rfb/TightQOIEncoder.h | 10 +- common/rfb/TightWEBPEncoder.cxx | 2 +- common/rfb/TightWEBPEncoder.h | 2 +- common/rfb/VNCSConnectionST.cxx | 15 +- common/rfb/VNCSConnectionST.h | 3 +- common/rfb/VNCServerST.cxx | 20 +- common/rfb/VNCServerST.h | 14 +- common/rfb/ZRLEEncoder.cxx | 2 +- common/rfb/ZRLEEncoder.h | 10 +- common/rfb/benchmark/benchmark.cxx | 2 + common/rfb/clipboardTypes.h | 24 +- common/rfb/encoders/FFMPEGVAAPIEncoder.cxx | 24 +- common/rfb/encoders/FFMPEGVAAPIEncoder.h | 3 +- common/rfb/encoders/KasmVideoConstants.h | 366 +++++++++++++++++-- common/rfb/encoders/ScreenEncoderManager.cxx | 98 ++--- common/rfb/encoders/ScreenEncoderManager.h | 39 +- common/rfb/encoders/SoftwareEncoder.cxx | 25 +- common/rfb/encoders/SoftwareEncoder.h | 3 +- common/rfb/encoders/VAAPIEncoder.cxx | 2 +- common/rfb/encoders/VAAPIEncoder.h | 2 +- common/rfb/encoders/VideoEncoderFactory.cxx | 8 + common/rfb/encodings.h | 151 ++++---- common/rfb/msgTypes.h | 75 ++-- 44 files changed, 844 insertions(+), 442 deletions(-) diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx index 6624849..46aecad 100644 --- a/common/rfb/ConnParams.cxx +++ b/common/rfb/ConnParams.cxx @@ -157,7 +157,8 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) encodings_.clear(); encodings_.insert(encodingRaw); - bool canChangeSettings = !shandler || shandler->canChangeKasmSettings(); + const bool canChangeSettings = !shandler || shandler->canChangeKasmSettings(); + const bool can_apply = !rfb::Server::ignoreClientSettingsKasm && canChangeSettings; for (int i = nEncodings-1; i >= 0; i--) { switch (encodings[i]) { @@ -283,116 +284,90 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) clientparlog("fineQualityLevel", fineQualityLevel, true); } - if (!rfb::Server::ignoreClientSettingsKasm && canChangeSettings) { - if (encodings[i] >= pseudoEncodingJpegVideoQualityLevel0 && - encodings[i] <= pseudoEncodingJpegVideoQualityLevel9) { - Server::jpegVideoQuality.setParam(encodings[i] - pseudoEncodingJpegVideoQualityLevel0); - clientparlog("jpegVideoQuality", encodings[i] - pseudoEncodingJpegVideoQualityLevel0, true); - } + if (encodings[i] >= pseudoEncodingJpegVideoQualityLevel0 && encodings[i] <= pseudoEncodingJpegVideoQualityLevel9) { + if (can_apply) + Server::jpegVideoQuality.setParam(encodings[i] - pseudoEncodingJpegVideoQualityLevel0); + clientparlog("jpegVideoQuality", encodings[i] - pseudoEncodingJpegVideoQualityLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingWebpVideoQualityLevel0 && - encodings[i] <= pseudoEncodingWebpVideoQualityLevel9) { - Server::webpVideoQuality.setParam(encodings[i] - pseudoEncodingWebpVideoQualityLevel0); - clientparlog("webpVideoQuality", encodings[i] - pseudoEncodingWebpVideoQualityLevel0, true); - } + if (encodings[i] >= pseudoEncodingWebpVideoQualityLevel0 && encodings[i] <= pseudoEncodingWebpVideoQualityLevel9) { + if (can_apply) + Server::webpVideoQuality.setParam(encodings[i] - pseudoEncodingWebpVideoQualityLevel0); + clientparlog("webpVideoQuality", encodings[i] - pseudoEncodingWebpVideoQualityLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingTreatLosslessLevel0 && - encodings[i] <= pseudoEncodingTreatLosslessLevel10) { - Server::treatLossless.setParam(encodings[i] - pseudoEncodingTreatLosslessLevel0); - clientparlog("treatLossless", encodings[i] - pseudoEncodingTreatLosslessLevel0, true); - } + if (encodings[i] >= pseudoEncodingTreatLosslessLevel0 && encodings[i] <= pseudoEncodingTreatLosslessLevel10) { + if (can_apply) + Server::treatLossless.setParam(encodings[i] - pseudoEncodingTreatLosslessLevel0); + clientparlog("treatLossless", encodings[i] - pseudoEncodingTreatLosslessLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingDynamicQualityMinLevel0 && - encodings[i] <= pseudoEncodingDynamicQualityMinLevel9) { - Server::dynamicQualityMin.setParam(encodings[i] - pseudoEncodingDynamicQualityMinLevel0); - clientparlog("dynamicQualityMin", encodings[i] - pseudoEncodingDynamicQualityMinLevel0, true); - } + if (encodings[i] >= pseudoEncodingDynamicQualityMinLevel0 && encodings[i] <= pseudoEncodingDynamicQualityMinLevel9) { + if (can_apply) + Server::dynamicQualityMin.setParam(encodings[i] - pseudoEncodingDynamicQualityMinLevel0); + clientparlog("dynamicQualityMin", encodings[i] - pseudoEncodingDynamicQualityMinLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingDynamicQualityMaxLevel0 && - encodings[i] <= pseudoEncodingDynamicQualityMaxLevel9) { - Server::dynamicQualityMax.setParam(encodings[i] - pseudoEncodingDynamicQualityMaxLevel0); - clientparlog("dynamicQualityMax", encodings[i] - pseudoEncodingDynamicQualityMaxLevel0, true); - } + if (encodings[i] >= pseudoEncodingDynamicQualityMaxLevel0 && encodings[i] <= pseudoEncodingDynamicQualityMaxLevel9) { + if (can_apply) + Server::dynamicQualityMax.setParam(encodings[i] - pseudoEncodingDynamicQualityMaxLevel0); + clientparlog("dynamicQualityMax", encodings[i] - pseudoEncodingDynamicQualityMaxLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingVideoAreaLevel1 && - encodings[i] <= pseudoEncodingVideoAreaLevel100) { - Server::videoArea.setParam(encodings[i] - pseudoEncodingVideoAreaLevel1 + 1); - clientparlog("videoArea", encodings[i] - pseudoEncodingVideoAreaLevel1 + 1, true); - } + if (encodings[i] >= pseudoEncodingVideoAreaLevel1 && encodings[i] <= pseudoEncodingVideoAreaLevel100) { + if (can_apply) + Server::videoArea.setParam(encodings[i] - pseudoEncodingVideoAreaLevel1 + 1); + clientparlog("videoArea", encodings[i] - pseudoEncodingVideoAreaLevel1 + 1, can_apply); + } - if (encodings[i] >= pseudoEncodingVideoTimeLevel0 && - encodings[i] <= pseudoEncodingVideoTimeLevel100) { - Server::videoTime.setParam(encodings[i] - pseudoEncodingVideoTimeLevel0); - clientparlog("videoTime", encodings[i] - pseudoEncodingVideoTimeLevel0, true); - } + if (encodings[i] >= pseudoEncodingVideoTimeLevel0 && encodings[i] <= pseudoEncodingVideoTimeLevel100) { + if (can_apply) + Server::videoTime.setParam(encodings[i] - pseudoEncodingVideoTimeLevel0); + clientparlog("videoTime", encodings[i] - pseudoEncodingVideoTimeLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingVideoOutTimeLevel1 && - encodings[i] <= pseudoEncodingVideoOutTimeLevel100) { - Server::videoOutTime.setParam(encodings[i] - pseudoEncodingVideoOutTimeLevel1 + 1); - clientparlog("videoOutTime", encodings[i] - pseudoEncodingVideoOutTimeLevel1 + 1, true); - } + if (encodings[i] >= pseudoEncodingVideoOutTimeLevel1 && encodings[i] <= pseudoEncodingVideoOutTimeLevel100) { + if (can_apply) + Server::videoOutTime.setParam(encodings[i] - pseudoEncodingVideoOutTimeLevel1 + 1); + clientparlog("videoOutTime", encodings[i] - pseudoEncodingVideoOutTimeLevel1 + 1, can_apply); + } - if (encodings[i] >= pseudoEncodingFrameRateLevel10 && - encodings[i] <= pseudoEncodingFrameRateLevel60) { - Server::frameRate.setParam(encodings[i] - pseudoEncodingFrameRateLevel10 + 10); - clientparlog("frameRate", encodings[i] - pseudoEncodingFrameRateLevel10 + 10, true); - } + if (encodings[i] >= pseudoEncodingFrameRateLevel10 && encodings[i] <= pseudoEncodingFrameRateLevel60) { + if (can_apply) + Server::frameRate.setParam(encodings[i] - pseudoEncodingFrameRateLevel10 + 10); + clientparlog("frameRate", encodings[i] - pseudoEncodingFrameRateLevel10 + 10, can_apply); + } - if (encodings[i] >= pseudoEncodingVideoScalingLevel0 && - encodings[i] <= pseudoEncodingVideoScalingLevel9) { - Server::videoScaling.setParam(encodings[i] - pseudoEncodingVideoScalingLevel0); - clientparlog("videoScaling", encodings[i] - pseudoEncodingVideoScalingLevel0, true); - } - } else { - if (encodings[i] >= pseudoEncodingJpegVideoQualityLevel0 && - encodings[i] <= pseudoEncodingJpegVideoQualityLevel9) { - clientparlog("jpegVideoQuality", encodings[i] - pseudoEncodingJpegVideoQualityLevel0, false); - } + if (encodings[i] >= pseudoEncodingVideoScalingLevel0 && encodings[i] <= pseudoEncodingVideoScalingLevel9) { + if (can_apply) + Server::videoScaling.setParam(encodings[i] - pseudoEncodingVideoScalingLevel0); + clientparlog("videoScaling", encodings[i] - pseudoEncodingVideoScalingLevel0, can_apply); + } - if (encodings[i] >= pseudoEncodingWebpVideoQualityLevel0 && - encodings[i] <= pseudoEncodingWebpVideoQualityLevel9) { - clientparlog("webpVideoQuality", encodings[i] - pseudoEncodingWebpVideoQualityLevel0, false); - } + // encs.push(encodings.pseudoEncodingStreamingMode + this.streamMode); - if (encodings[i] >= pseudoEncodingTreatLosslessLevel0 && - encodings[i] <= pseudoEncodingTreatLosslessLevel10) { - clientparlog("treatLossless", encodings[i] - pseudoEncodingTreatLosslessLevel0, false); - } + // if (encodings[i] >= pseudoEncodingHardwareProfile0 && encodings[i] <= pseudoEncodingHardwareProfile4) { + // if (appliable) + // Server::hardwareProfile.setParam(encodings[i] - pseudoEncodingHardwareProfile0); + // clientparlog("hardwareProfile", encodings[i] - pseudoEncodingHardwareProfile0, appliable); + // } - if (encodings[i] >= pseudoEncodingDynamicQualityMinLevel0 && - encodings[i] <= pseudoEncodingDynamicQualityMinLevel9) { - clientparlog("dynamicQualityMin", encodings[i] - pseudoEncodingDynamicQualityMinLevel0, false); - } + if (encodings[i] >= pseudoEncodingGOP1 && encodings[i] <= pseudoEncodingGOP60) { + if (can_apply) + Server::groupOfPicture.setParam(encodings[i] - pseudoEncodingGOP1); + clientparlog("groupOfPicture", encodings[i] - pseudoEncodingGOP1, can_apply); + } - if (encodings[i] >= pseudoEncodingDynamicQualityMaxLevel0 && - encodings[i] <= pseudoEncodingDynamicQualityMaxLevel9) { - clientparlog("dynamicQualityMax", encodings[i] - pseudoEncodingDynamicQualityMaxLevel0, false); - } + if (encodings[i] >= pseudoEncodingStreamingVideoQualityLevel0 && encodings[i] <= pseudoEncodingStreamingVideoQualityLevel63) { + if (can_apply) + Server::videoQualityCRFCQP.setParam(pseudoEncodingStreamingVideoQualityLevel63 - encodings[i]); + clientparlog("videoQualityCRFCQP", pseudoEncodingStreamingVideoQualityLevel63 - encodings[i], can_apply); + } - if (encodings[i] >= pseudoEncodingVideoAreaLevel1 && - encodings[i] <= pseudoEncodingVideoAreaLevel100) { - clientparlog("videoArea", encodings[i] - pseudoEncodingVideoAreaLevel1 + 1, false); - } - - if (encodings[i] >= pseudoEncodingVideoTimeLevel0 && - encodings[i] <= pseudoEncodingVideoTimeLevel100) { - clientparlog("videoTime", encodings[i] - pseudoEncodingVideoTimeLevel0, false); - } - - if (encodings[i] >= pseudoEncodingVideoOutTimeLevel1 && - encodings[i] <= pseudoEncodingVideoOutTimeLevel100) { - clientparlog("videoOutTime", encodings[i] - pseudoEncodingVideoOutTimeLevel1 + 1, false); - } - - if (encodings[i] >= pseudoEncodingFrameRateLevel10 && - encodings[i] <= pseudoEncodingFrameRateLevel60) { - clientparlog("frameRate", encodings[i] - pseudoEncodingFrameRateLevel10 + 10, false); - } - - if (encodings[i] >= pseudoEncodingVideoScalingLevel0 && - encodings[i] <= pseudoEncodingVideoScalingLevel9) { - clientparlog("videoScaling", encodings[i] - pseudoEncodingVideoScalingLevel0, false); - } + if (encodings[i] >=pseudoEncodingStreamingModeAV1QSV && encodings[i] <= pseudoEncodingStreamingModeJpegWebp) { + if (can_apply) + encoder = KasmVideoEncoders::from_encoding(encodings[i]); + clientparlog("Encoder", encodings[i], can_apply); } if (encodings[i] > 0) diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h index 96ce5cd..8541f2c 100644 --- a/common/rfb/ConnParams.h +++ b/common/rfb/ConnParams.h @@ -29,18 +29,19 @@ #include #include #include +#include namespace rdr { class InStream; } namespace rfb { - const int subsampleUndefined = -1; - const int subsampleNone = 0; - const int subsampleGray = 1; - const int subsample2X = 2; - const int subsample4X = 3; - const int subsample8X = 4; - const int subsample16X = 5; + constexpr int subsampleUndefined = -1; + constexpr int subsampleNone = 0; + constexpr int subsampleGray = 1; + constexpr int subsample2X = 2; + constexpr int subsample4X = 3; + constexpr int subsample8X = 4; + constexpr int subsample16X = 5; class SMsgHandler; @@ -91,7 +92,7 @@ namespace rfb { void setEncodings(int nEncodings, const rdr::S32* encodings); - unsigned int ledState() { return ledState_; } + unsigned int ledState() const { return ledState_; } void setLEDState(unsigned int state); rdr::U32 clipboardFlags() const { return clipFlags; } @@ -143,6 +144,8 @@ namespace rfb { }; bool kasmPassed[KASM_NUM_SETTINGS]; + KasmVideoEncoders::Encoder encoder{KasmVideoEncoders::Encoder::unavailable}; + KasmVideoEncoders::Encoders available_encoders; private: diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 4ecc296..1e449e1 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -167,9 +167,9 @@ static void updateMaxVideoRes(uint16_t *x, uint16_t *y) { } } -EncodeManager::EncodeManager(SConnection *conn_, EncCache *encCache_, const FFmpeg& ffmpeg) : +EncodeManager::EncodeManager(SConnection *conn_, EncCache *encCache_, const FFmpeg& ffmpeg_) : conn(conn_), dynamicQualityMin(-1), dynamicQualityOff(-1), areaCur(0), videoDetected(false), videoTimer(this), - watermarkStats(0), maxEncodingTime(0), framesSinceEncPrint(0), ffmpeg_available(ffmpeg.is_available()), encCache(encCache_) + watermarkStats(0), maxEncodingTime(0), framesSinceEncPrint(0), ffmpeg(ffmpeg_), ffmpeg_available(ffmpeg.is_available()), encCache(encCache_) { encoders.resize(encoderClassMax, nullptr); activeEncoders.resize(encoderTypeMax, encoderRaw); @@ -437,24 +437,41 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, writeCopyRects(copied, copyDelta); writeCopyPassRects(copypassed); - // If a video codec is enabled, send that stream constantly - /*if (ffmpeg_available && video_mode_available) { - startRect(pb->getRect(), encoderFullColour, true, STARTRECT_OVERRIDE_KASMVIDEO); + if (video_mode_available && conn->cp.encoder != KasmVideoEncoders::Encoder::unavailable) { - encoders[encoderKasmVideo]->writeRect(pb, Palette()); - - endRect(STARTRECT_OVERRIDE_KASMVIDEO); - }*/ - - if (video_mode_available) { - auto *screen_encoder_manager = dynamic_cast(encoders[encoderKasmVideo]); + auto begin = msSince(&start); + auto *screen_encoder_manager = dynamic_cast *>(encoders[encoderKasmVideo]); if (screen_encoder_manager) { + if (screen_encoder_manager->get_encoder() != conn->cp.encoder) { + delete encoders[encoderKasmVideo]; + + //puts("CHANGING ENCODER!!!"); + //puts("CHANGING ENCODER!!!"); + //puts("CHANGING ENCODER!!!"); + //puts("CHANGING ENCODER!!!"); + //puts("CHANGING ENCODER!!!"); + + encoders[encoderKasmVideo] = new ScreenEncoderManager(ffmpeg, + conn->cp.encoder, + video_encoders::available_encoders, + conn, + {0, + 0, + static_cast(Server::frameRate), + static_cast(Server::groupOfPicture), + static_cast(Server::videoQualityCRFCQP)}); + + } screen_encoder_manager->sync_layout(layout); - for (auto screen_encoder: *screen_encoder_manager) { - uint32_t screen_id = screen_encoder->getId(); - auto *encoder = startRect(pb->getRect(), encoderFullColour, true, STARTRECT_OVERRIDE_KASMVIDEO); - screen_encoder->writeRect(pb, Palette()); + const Palette palette; + + for (auto &screen: *screen_encoder_manager) { + if (!screen.encoder) + continue; + + startRect(screen.layout.dimensions, encoderFullColour, true, STARTRECT_OVERRIDE_KASMVIDEO); + screen.encoder->writeRect(pb, palette); endRect(STARTRECT_OVERRIDE_KASMVIDEO); } } @@ -462,6 +479,10 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, std::vector rects; changed.get_rects(&rects); updateVideoStats(rects, pb); + + auto end = msSince(&start) - begin; + + printf("ENCODING TOOK: %d ms\n", end); } else { /* * We start by searching for solid rects, which are then removed @@ -747,7 +768,7 @@ Encoder *EncodeManager::startRect(const Rect &rect, int type, const bool trackQu return encoder; } -void EncodeManager::endRect(const enum startRectOverride overrider) +void EncodeManager::endRect(const startRectOverride overrider) { conn->writer()->endRect(); const auto length = conn->getOutStream(conn->cp.supportsUdp)->length() - beforeLength; diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h index 0ae1cfb..57bdf75 100644 --- a/common/rfb/EncodeManager.h +++ b/common/rfb/EncodeManager.h @@ -216,6 +216,7 @@ namespace rfb { unsigned maxEncodingTime, framesSinceEncPrint; unsigned scalingTime; + const FFmpeg &ffmpeg; bool ffmpeg_available; bool video_mode_available{false}; diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index 00daaec..52d2b60 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -50,7 +50,7 @@ namespace rfb { // isSupported() should return a boolean indicating if this encoder // is okay to use with the current connection. This usually involves // checking the list of encodings in the connection parameters. - virtual bool isSupported()=0; + virtual bool isSupported() const = 0; virtual void setCompressLevel(int level) {}; virtual void setQualityLevel(int level) {}; diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index 418a440..c6ad3a0 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -49,11 +49,7 @@ HextileEncoder::HextileEncoder(SConnection* conn) : { } -HextileEncoder::~HextileEncoder() -{ -} - -bool HextileEncoder::isSupported() +bool HextileEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingHextile); } diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h index 393ab23..e5af2b3 100644 --- a/common/rfb/HextileEncoder.h +++ b/common/rfb/HextileEncoder.h @@ -23,15 +23,13 @@ namespace rfb { - class HextileEncoder : public Encoder { - public: - HextileEncoder(SConnection* conn); - virtual ~HextileEncoder(); - virtual bool isSupported(); - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); - virtual void writeSolidRect(int width, int height, - const PixelFormat& pf, - const rdr::U8* colour); - }; + class HextileEncoder : public Encoder { + public: + HextileEncoder(SConnection* conn); + ~HextileEncoder() override = default; + bool isSupported() const override; + void writeRect(const PixelBuffer* pb, const Palette& palette) override; + void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override; + }; } #endif diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index 60a0663..24032bc 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -41,11 +41,7 @@ RREEncoder::RREEncoder(SConnection* conn) : { } -RREEncoder::~RREEncoder() -{ -} - -bool RREEncoder::isSupported() +bool RREEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingRRE); } diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h index c0de999..f8a9d16 100644 --- a/common/rfb/RREEncoder.h +++ b/common/rfb/RREEncoder.h @@ -28,12 +28,12 @@ namespace rfb { class RREEncoder : public Encoder { public: RREEncoder(SConnection* conn); - virtual ~RREEncoder(); - virtual bool isSupported(); - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); - virtual void writeSolidRect(int width, int height, + ~RREEncoder() override = default; + bool isSupported() const override; + void writeRect(const PixelBuffer* pb, const Palette& palette) override; + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; private: rdr::MemOutStream mos; ManagedPixelBuffer bufferCopy; diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx index 4090427..a84ab5c 100644 --- a/common/rfb/RawEncoder.cxx +++ b/common/rfb/RawEncoder.cxx @@ -29,11 +29,7 @@ RawEncoder::RawEncoder(SConnection* conn) : { } -RawEncoder::~RawEncoder() -{ -} - -bool RawEncoder::isSupported() +bool RawEncoder::isSupported() const { // Implicitly required; return true; diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h index ee98d4a..f113147 100644 --- a/common/rfb/RawEncoder.h +++ b/common/rfb/RawEncoder.h @@ -26,12 +26,12 @@ namespace rfb { class RawEncoder : public Encoder { public: RawEncoder(SConnection* conn); - virtual ~RawEncoder(); - virtual bool isSupported(); - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); - virtual void writeSolidRect(int width, int height, + ~RawEncoder() override = default; + bool isSupported() const override; + void writeRect(const PixelBuffer* pb, const Palette& palette) override; + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; }; } #endif diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index b8a6e7f..06a1e6f 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -101,6 +101,7 @@ namespace rfb { virtual void subscribeUnixRelay(const char *name) = 0; virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len) = 0; + virtual void videoEncodersRequest(const std::vector &encoders) = 0; ConnParams cp; }; diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 933b1d8..f0ba4c8 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -53,7 +53,7 @@ void SMsgReader::readClientInit() void SMsgReader::readMsg() { - int msgType = is->readU8(); + const int msgType = is->readU8(); switch (msgType) { case msgTypeSetPixelFormat: readSetPixelFormat(); @@ -106,6 +106,9 @@ void SMsgReader::readMsg() case msgTypeUnixRelay: readUnixRelay(); break; + case msgTypeVideoEncoders: + readVideoEncodersRequest(); + break; case msgTypeKeepAlive: readKeepAlive(); break; @@ -413,3 +416,13 @@ void SMsgReader::readUnixRelay() handler->unixRelay(name, buf, len); } + +void SMsgReader::readVideoEncodersRequest() const { + const auto len = is->readU8(); + std::vector buf(len); + + for (int i = 0; i < len; ++i) + buf[i] = is->readU32(); + + handler->videoEncodersRequest(buf); +} diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h index 77af609..df08969 100644 --- a/common/rfb/SMsgReader.h +++ b/common/rfb/SMsgReader.h @@ -68,6 +68,7 @@ namespace rfb { void readSubscribeUnixRelay(); void readUnixRelay(); + void readVideoEncodersRequest() const; SMsgHandler* handler; rdr::InStream* is; diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 0282a17..c0ce9c1 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -778,6 +778,26 @@ void SMsgWriter::writeUnixRelay(const char *name, const rdr::U8 *buf, const unsi endMsg(); } +void SMsgWriter::writeVideoEncoders(const std::vector &encoders) { + startMsg(msgTypeVideoEncoders); + + std::vector conjunction; + + for (const auto encoder: cp->available_encoders) { + if (std::ranges::find(encoders, KasmVideoEncoders::to_streaming_mode(encoder)) != encoders.end()) { + conjunction.push_back(KasmVideoEncoders::to_encoding(encoder)); + } + } + + const uint8_t size = conjunction.size(); + os->writeU8(size); + + for (auto encoder: conjunction) + os->writeS32(encoder); + + endMsg(); +} + void SMsgWriter::writeUserJoinedSession(const std::string& username) { startMsg(msgTypeUserAddedToSession); diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 646c51a..4075481 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -132,6 +132,7 @@ namespace rfb { void writeSubscribeUnixRelay(const bool success, const char *msg); void writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len); + void writeVideoEncoders(const std::vector &encoders); void writeUserJoinedSession(const std::string& username); void writeUserLeftSession(const std::string& username); diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index dc28e0c..eced95e 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -62,11 +62,7 @@ TightEncoder::TightEncoder(SConnection* conn) : setCompressLevel(-1); } -TightEncoder::~TightEncoder() -{ -} - -bool TightEncoder::isSupported() +bool TightEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingTight); } diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h index 222b636..16c2148 100644 --- a/common/rfb/TightEncoder.h +++ b/common/rfb/TightEncoder.h @@ -29,16 +29,16 @@ namespace rfb { class TightEncoder : public Encoder { public: TightEncoder(SConnection* conn); - virtual ~TightEncoder(); + ~TightEncoder() override = default; - virtual bool isSupported(); + bool isSupported() const override; - virtual void setCompressLevel(int level); + void setCompressLevel(int level) override; - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); - virtual void writeSolidRect(int width, int height, + void writeRect(const PixelBuffer* pb, const Palette& palette) override; + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; void writeWatermarkRect(const rdr::U8 *data, const unsigned len, const rdr::U8 r, const rdr::U8 g, diff --git a/common/rfb/TightJPEGEncoder.cxx b/common/rfb/TightJPEGEncoder.cxx index 8311725..f48d266 100644 --- a/common/rfb/TightJPEGEncoder.cxx +++ b/common/rfb/TightJPEGEncoder.cxx @@ -76,11 +76,7 @@ TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) : { } -TightJPEGEncoder::~TightJPEGEncoder() -{ -} - -bool TightJPEGEncoder::isSupported() +bool TightJPEGEncoder::isSupported() const { if (!conn->cp.supportsEncoding(encodingTight)) return false; diff --git a/common/rfb/TightJPEGEncoder.h b/common/rfb/TightJPEGEncoder.h index cc7c77e..25f2ceb 100644 --- a/common/rfb/TightJPEGEncoder.h +++ b/common/rfb/TightJPEGEncoder.h @@ -30,22 +30,22 @@ namespace rfb { class TightJPEGEncoder : public Encoder { public: TightJPEGEncoder(SConnection* conn); - virtual ~TightJPEGEncoder(); + ~TightJPEGEncoder() override = default; - virtual bool isSupported(); + bool isSupported() const override; - virtual void setQualityLevel(int level); - virtual void setFineQualityLevel(int quality, int subsampling); + void setQualityLevel(int level) override; + void setFineQualityLevel(int quality, int subsampling) override; - virtual bool treatLossless(); + bool treatLossless() override; - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); + void writeRect(const PixelBuffer* pb, const Palette& palette) override; virtual void compressOnly(const PixelBuffer* pb, const uint8_t quality, std::vector &out, const bool lowVideoQuality) const; virtual void writeOnly(const std::vector &out) const; - virtual void writeSolidRect(int width, int height, + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; protected: void writeCompact(rdr::U32 value, rdr::OutStream* os) const; diff --git a/common/rfb/TightQOIEncoder.cxx b/common/rfb/TightQOIEncoder.cxx index c9c977d..b56bcb3 100644 --- a/common/rfb/TightQOIEncoder.cxx +++ b/common/rfb/TightQOIEncoder.cxx @@ -156,11 +156,7 @@ TightQOIEncoder::TightQOIEncoder(SConnection* conn) : { } -TightQOIEncoder::~TightQOIEncoder() -{ -} - -bool TightQOIEncoder::isSupported() +bool TightQOIEncoder::isSupported() const { if (!conn->cp.supportsEncoding(encodingTight)) return false; diff --git a/common/rfb/TightQOIEncoder.h b/common/rfb/TightQOIEncoder.h index 050d508..84ec84d 100644 --- a/common/rfb/TightQOIEncoder.h +++ b/common/rfb/TightQOIEncoder.h @@ -27,17 +27,17 @@ namespace rfb { class TightQOIEncoder : public Encoder { public: TightQOIEncoder(SConnection* conn); - virtual ~TightQOIEncoder(); + ~TightQOIEncoder() override = default; - virtual bool isSupported(); + bool isSupported() const override; - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); + void writeRect(const PixelBuffer* pb, const Palette& palette) override; virtual void compressOnly(const PixelBuffer* pb, const uint8_t quality, std::vector &out, const bool lowVideoQuality) const; virtual void writeOnly(const std::vector &out) const; - virtual void writeSolidRect(int width, int height, + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; protected: void writeCompact(rdr::U32 value, rdr::OutStream* os) const; diff --git a/common/rfb/TightWEBPEncoder.cxx b/common/rfb/TightWEBPEncoder.cxx index 2e79c6c..3a4d3f2 100644 --- a/common/rfb/TightWEBPEncoder.cxx +++ b/common/rfb/TightWEBPEncoder.cxx @@ -90,7 +90,7 @@ TightWEBPEncoder::~TightWEBPEncoder() { } -bool TightWEBPEncoder::isSupported() +bool TightWEBPEncoder::isSupported() const { if (!conn->cp.supportsEncoding(encodingTight)) return false; diff --git a/common/rfb/TightWEBPEncoder.h b/common/rfb/TightWEBPEncoder.h index 6b9fa23..ab6c34a 100644 --- a/common/rfb/TightWEBPEncoder.h +++ b/common/rfb/TightWEBPEncoder.h @@ -29,7 +29,7 @@ namespace rfb { TightWEBPEncoder(SConnection* conn); virtual ~TightWEBPEncoder(); - virtual bool isSupported(); + bool isSupported() const override; virtual void setQualityLevel(int level); virtual void setFineQualityLevel(int quality, int subsampling); diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 8e5c26b..fd89fb4 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -41,6 +41,7 @@ #include #include +#include "encoders/EncoderProbe.h" #include "kasmpasswd.h" using namespace rfb; @@ -89,9 +90,11 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, user[0] = '\0'; const char *at = strrchr(peerEndpoint.buf, '@'); - if (at && at - peerEndpoint.buf > 1 && at - peerEndpoint.buf < USERNAME_LEN) { - memcpy(user, peerEndpoint.buf, at - peerEndpoint.buf); - user[at - peerEndpoint.buf] = '\0'; + + const auto offset = at - peerEndpoint.buf; + if (at && offset > 1 && static_cast(offset) < USERNAME_LEN) { + memcpy(user, peerEndpoint.buf, offset); + user[offset] = '\0'; } bool read, write, owner; @@ -112,6 +115,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, gettimeofday(&lastClipboardOp, nullptr); gettimeofday(&lastKeyEvent, nullptr); + cp.available_encoders = video_encoders::available_encoders; + server->clients.push_front(this); if (server->apimessager) @@ -1908,6 +1913,10 @@ void VNCSConnectionST::unixRelay(const char *name, const rdr::U8 *buf, const uns } } +void VNCSConnectionST::videoEncodersRequest(const std::vector &encoders) { + writer()->writeVideoEncoders(encoders); +} + void VNCSConnectionST::sendUnixRelayData(const char name[], const unsigned char *buf, const unsigned len) { diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index f8157b5..b1d48b7 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -258,12 +258,13 @@ namespace rfb { virtual void udpUpgrade(const char *resp); virtual void subscribeUnixRelay(const char *name); virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len); + void videoEncodersRequest(std::vector const &encoders) override; virtual void supportsLocalCursor(); virtual void supportsFence(); virtual void supportsContinuousUpdates(); virtual void supportsLEDState(); - virtual bool canChangeKasmSettings() const { + bool canChangeKasmSettings() const override { return (accessRights & (AccessPtrEvents | AccessKeyEvents)) == (AccessPtrEvents | AccessKeyEvents); } diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index bec1882..c5b06ce 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -160,7 +160,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) std::string available_accelerators{}; for (const auto encoder: video_encoders::available_encoders) { - if (encoder != KasmVideoEncoders::Encoder::h264_software) { + if (KasmVideoEncoders::is_accelerated(encoder)) { if (!available_accelerators.empty()) available_accelerators.append(", "); @@ -168,8 +168,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) } } - const auto str = available_accelerators; - slog.info("Hardware video encoding acceleration capability: %s", str.empty() ? "none" : str.c_str()); + slog.info("Hardware video encoding acceleration capability: %s", + available_accelerators.empty() ? "none" : available_accelerators.c_str()); DLPRegion.enabled = DLPRegion.percents = false; @@ -259,6 +259,20 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) if (selected_codec[0] && !SupportedVideoEncoders::is_supported(selected_codec)) throw std::invalid_argument(fmt::format("Unknown video codec: {}", selected_codec)); + const auto selected_encoders = SupportedVideoEncoders::parse(selected_codec); + + for (auto encoder: video_encoders::available_encoders) { + if (std::ranges::find(selected_encoders, encoder) != selected_encoders.end()) + encoders.push_back(encoder); + } + + std::string encoder_names; + + for (auto encoder: encoders) + encoder_names.append(KasmVideoEncoders::to_string(encoder)).append(" "); + + slog.info("Using CLI-specified video codecs (supported subset): %s", encoder_names.c_str()); + if (Server::selfBench) SelfBench(); diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 91309c4..9d45484 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -26,15 +26,16 @@ #include -#include -#include -#include -#include +#include #include #include -#include -#include +#include +#include +#include #include +#include +#include +#include #include namespace rfb { @@ -237,6 +238,7 @@ namespace rfb { std::list closingSockets; static EncCache encCache; + std::vector encoders{}; ComparingUpdateTracker* comparer; diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index f1a3262..cc9311e 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -41,7 +41,7 @@ ZRLEEncoder::~ZRLEEncoder() zos.setUnderlying(NULL); } -bool ZRLEEncoder::isSupported() +bool ZRLEEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingZRLE); } diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index d61bab1..3fb3ad9 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -28,14 +28,14 @@ namespace rfb { class ZRLEEncoder : public Encoder { public: ZRLEEncoder(SConnection* conn); - virtual ~ZRLEEncoder(); + ~ZRLEEncoder() override; - virtual bool isSupported(); + bool isSupported() const override; - virtual void writeRect(const PixelBuffer* pb, const Palette& palette); - virtual void writeSolidRect(int width, int height, + void writeRect(const PixelBuffer* pb, const Palette& palette) override; + void writeSolidRect(int width, int height, const PixelFormat& pf, - const rdr::U8* colour); + const rdr::U8* colour) override; protected: void writePaletteTile(const Rect& tile, const PixelBuffer* pb, diff --git a/common/rfb/benchmark/benchmark.cxx b/common/rfb/benchmark/benchmark.cxx index df12050..632fa76 100644 --- a/common/rfb/benchmark/benchmark.cxx +++ b/common/rfb/benchmark/benchmark.cxx @@ -118,6 +118,8 @@ namespace benchmarking { void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len) override {} + void videoEncodersRequest(const std::vector &encoders) override {} + void handleFrameStats(rdr::U32 all, rdr::U32 render) override {} [[nodiscard]] auto getJpegStats() const { diff --git a/common/rfb/clipboardTypes.h b/common/rfb/clipboardTypes.h index bd3fa03..01fbec3 100644 --- a/common/rfb/clipboardTypes.h +++ b/common/rfb/clipboardTypes.h @@ -21,21 +21,21 @@ namespace rfb { // Formats - const unsigned int clipboardUTF8 = 1 << 0; - const unsigned int clipboardRTF = 1 << 1; - const unsigned int clipboardHTML = 1 << 2; - const unsigned int clipboardDIB = 1 << 3; - const unsigned int clipboardFiles = 1 << 4; + constexpr unsigned int clipboardUTF8 = 1 << 0; + constexpr unsigned int clipboardRTF = 1 << 1; + constexpr unsigned int clipboardHTML = 1 << 2; + constexpr unsigned int clipboardDIB = 1 << 3; + constexpr unsigned int clipboardFiles = 1 << 4; - const unsigned int clipboardFormatMask = 0x0000ffff; + constexpr unsigned int clipboardFormatMask = 0x0000ffff; // Actions - const unsigned int clipboardCaps = 1 << 24; - const unsigned int clipboardRequest = 1 << 25; - const unsigned int clipboardPeek = 1 << 26; - const unsigned int clipboardNotify = 1 << 27; - const unsigned int clipboardProvide = 1 << 28; + constexpr unsigned int clipboardCaps = 1 << 24; + constexpr unsigned int clipboardRequest = 1 << 25; + constexpr unsigned int clipboardPeek = 1 << 26; + constexpr unsigned int clipboardNotify = 1 << 27; + constexpr unsigned int clipboardProvide = 1 << 28; - const unsigned int clipboardActionMask = 0xff000000; + constexpr unsigned int clipboardActionMask = 0xff000000; } #endif diff --git a/common/rfb/encoders/FFMPEGVAAPIEncoder.cxx b/common/rfb/encoders/FFMPEGVAAPIEncoder.cxx index 3774328..5f812ec 100644 --- a/common/rfb/encoders/FFMPEGVAAPIEncoder.cxx +++ b/common/rfb/encoders/FFMPEGVAAPIEncoder.cxx @@ -19,7 +19,7 @@ namespace rfb { FFMPEGVAAPIEncoder::FFMPEGVAAPIEncoder(Screen layout_, const FFmpeg &ffmpeg_, SConnection *conn, KasmVideoEncoders::Encoder encoder_, VideoEncoderParams params) : Encoder(layout_.id, conn, encodingKasmVideo, static_cast(EncoderUseNativePF | EncoderLossy), -1), layout(layout_), - ffmpeg(ffmpeg_), encoder(encoder_), current_params(params) { + ffmpeg(ffmpeg_), encoder(encoder_), current_params(params), msg_codec_id(KasmVideoEncoders::to_msg_id(encoder)) { AVBufferRef *hw_device_ctx{}; int err{}; @@ -29,9 +29,10 @@ namespace rfb { } hw_device_ctx_guard.reset(hw_device_ctx); - codec = ffmpeg.avcodec_find_encoder_by_name("h264_vaapi"); + const auto *enc_name = KasmVideoEncoders::to_string(encoder); + codec = ffmpeg.avcodec_find_encoder_by_name(enc_name); if (!codec) - throw std::runtime_error("Could not find h264_vaapi encoder"); + throw std::runtime_error(fmt::format("Could not find {} encoder", enc_name)); auto *frame = ffmpeg.av_frame_alloc(); if (!frame) @@ -160,14 +161,14 @@ namespace rfb { } auto *sws_ctx = ffmpeg.sws_getContext( - width, height, AV_PIX_FMT_RGB32, params.width, params.height, AV_PIX_FMT_NV12, SWS_BILINEAR, nullptr, nullptr, nullptr); + width, height, AV_PIX_FMT_RGB32, params.width, params.height, AV_PIX_FMT_NV12, SWS_BILINEAR, nullptr, nullptr, nullptr); sws_guard.reset(sws_ctx); return true; } - bool FFMPEGVAAPIEncoder::isSupported() { + bool FFMPEGVAAPIEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingKasmVideo); } @@ -191,10 +192,10 @@ namespace rfb { dst_height = height & ~1; VideoEncoderParams params{dst_width, - dst_height, - static_cast(Server::frameRate), - static_cast(Server::groupOfPicture), - static_cast(Server::videoQualityCRFCQP)}; + dst_height, + static_cast(Server::frameRate), + static_cast(Server::groupOfPicture), + static_cast(Server::videoQualityCRFCQP)}; if (current_params != params) { bpp = pb->getPF().bpp >> 3; @@ -221,7 +222,7 @@ namespace rfb { if (err = ffmpeg.av_hwframe_transfer_data(hw_frame_guard.get(), frame, 0); err < 0) { vlog.error( - "Error while transferring frame data to surface (%s). Error code: %d", ffmpeg.get_error_description(err).c_str(), err); + "Error while transferring frame data to surface (%s). Error code: %d", ffmpeg.get_error_description(err).c_str(), err); } if (err = ffmpeg.avcodec_send_frame(ctx_guard.get(), hw_frame_guard.get()); err < 0) { @@ -247,7 +248,8 @@ namespace rfb { vlog.debug("Key frame %ld", frame->pts); auto *os = conn->getOutStream(conn->cp.supportsUdp); - os->writeU8(kasmVideoH264 << 4); + os->writeU8(layout.id); + os->writeU8(msg_codec_id); os->writeU8(pkt->flags & AV_PKT_FLAG_KEY); write_compact(os, pkt->size); os->writeBytes(&pkt->data[0], pkt->size); diff --git a/common/rfb/encoders/FFMPEGVAAPIEncoder.h b/common/rfb/encoders/FFMPEGVAAPIEncoder.h index 416788c..cc02059 100644 --- a/common/rfb/encoders/FFMPEGVAAPIEncoder.h +++ b/common/rfb/encoders/FFMPEGVAAPIEncoder.h @@ -23,6 +23,7 @@ class FFMPEGVAAPIEncoder final : public Encoder, public VideoEncoder { KasmVideoEncoders::Encoder encoder; VideoEncoderParams current_params{}; + uint8_t msg_codec_id; int64_t pts{}; int bpp{}; @@ -36,7 +37,7 @@ class FFMPEGVAAPIEncoder final : public Encoder, public VideoEncoder { VideoEncoderParams params); public: - bool isSupported() override; + bool isSupported() const override; void writeRect(const PixelBuffer *pb, const Palette &palette) override; void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override; void writeSkipRect() override; diff --git a/common/rfb/encoders/KasmVideoConstants.h b/common/rfb/encoders/KasmVideoConstants.h index 42400bb..6694f4b 100644 --- a/common/rfb/encoders/KasmVideoConstants.h +++ b/common/rfb/encoders/KasmVideoConstants.h @@ -17,33 +17,273 @@ */ #pragma once +#include #include +#include #include +#include #include +#include +#include + +template +class EnumRange { +public: + using val_t = std::underlying_type_t; + + class EnumIterator { + val_t value; + + public: + explicit EnumIterator(E v) : + value(static_cast>(v)) {} + E operator*() const { + return static_cast(value); + } + EnumIterator &operator++() { + ++value; + return *this; + } + bool operator!=(const EnumIterator &other) const { + return value != other.value; + } + }; + + EnumRange(E begin, E end) : + begin_iter(EnumIterator(begin)), + end_iter(++EnumIterator(end)) {} + EnumIterator begin() const { + return begin_iter; + } + EnumIterator end() const { + return end_iter; + } + EnumIterator begin() { + return begin_iter; + } + EnumIterator end() { + return end_iter; + } + +private: + EnumIterator begin_iter; + EnumIterator end_iter; +}; + +template +auto enum_range(T begin, T end) { + return EnumRange(begin, end); +} namespace rfb { // Compression control - static constexpr unsigned int kasmVideoH264 = 0x01; // H.264 encoding + static constexpr unsigned int kasmVideoH264 = 0x01 << 4; // H.264 encoding + static constexpr unsigned int kasmVideoH265 = 0x02 << 4; // H.265 encoding + static constexpr unsigned int kasmVideoAV1 = 0x03 << 4; // AV1 encoding static constexpr unsigned int kasmVideoSkip = 0x00; // Skip frame - static constexpr int GroupOfPictureSize = 10; // interval between I-frames + static constexpr auto drm_device_paths = std::to_array({ + "/dev/dri/renderD128", + "/dev/dri/card0", + "/dev/dri/renderD129", + "/dev/dri/card1", + }); - static constexpr std::array drm_device_paths = { - "/dev/dri/renderD128", - "/dev/dri/card0", - "/dev/dri/renderD129", - "/dev/dri/card1", + struct KasmVideoEncoders { + // Codecs are ordered by preferred usage quality + enum class Encoder : uint8_t + { + av1_vaapi, + av1_ffmpeg_vaapi, + av1_nvenc, + av1_software, + + h265_vaapi, // h265 + h265_ffmpeg_vaapi, + h265_nvenc, + h265_software, + + h264_vaapi, + h264_ffmpeg_vaapi, + h264_nvenc, + h264_software, + + unavailable + }; + + using Encoders = std::vector; + + static inline auto EncoderNames = std::to_array({"av1_vaapi", + "av1_vaapi", + "av1_nvenc", + "libsvtav1", + + "hevc_vaapi", + "hevc_vaapi", + "hevc_nvenc", + "libx265", + + "h264_vaapi", + "h264_vaapi", + "h264_nvenc", + "libx264", + "unavailable"}); + + static inline auto Encodings = std::to_array({pseudoEncodingStreamingModeAV1VAAPI, + pseudoEncodingStreamingModeAV1VAAPI, + pseudoEncodingStreamingModeAV1NVENC, + pseudoEncodingStreamingModeAV1SW, + + pseudoEncodingStreamingModeHEVCVAAPI, + pseudoEncodingStreamingModeHEVCVAAPI, + pseudoEncodingStreamingModeHEVCNVENC, + pseudoEncodingStreamingModeHEVCSW, + + pseudoEncodingStreamingModeAVCVAAPI, + pseudoEncodingStreamingModeAVCVAAPI, + pseudoEncodingStreamingModeAVCNVENC, + pseudoEncodingStreamingModeAVCSW, + + pseudoEncodingStreamingModeJpegWebp}); + + static bool is_accelerated(Encoder encoder) { + return encoder != Encoder::h264_software && encoder != Encoder::h265_software && encoder != Encoder::av1_software; + } + + static std::string_view to_string(Encoder encoder) { + return EncoderNames[static_cast(encoder)]; + } + + static int to_encoding(Encoder encoder) { + return Encodings[static_cast(encoder)]; + } + + static Encoder from_encoding(int encoding) { + for (auto encoder: enum_range(Encoder::av1_vaapi, Encoder::unavailable)) { + if (to_encoding(encoder) == encoding) { + switch (encoder) { + case Encoder::av1_vaapi: + return Encoder::av1_ffmpeg_vaapi; + case Encoder::h265_vaapi: + return Encoder::h265_ffmpeg_vaapi; + case Encoder::h264_vaapi: + return Encoder::h264_ffmpeg_vaapi; + default: + return encoder; + } + } + } + + return Encoder::unavailable; + } + + static unsigned int to_msg_id(Encoder encoder) { + switch (encoder) { + case Encoder::av1_vaapi: + case Encoder::av1_ffmpeg_vaapi: + case Encoder::av1_nvenc: + case Encoder::av1_software: + return kasmVideoAV1; + case Encoder::h265_vaapi: // h265 + case Encoder::h265_ffmpeg_vaapi: + case Encoder::h265_nvenc: + case Encoder::h265_software: + return kasmVideoH265; + case Encoder::h264_vaapi: + case Encoder::h264_ffmpeg_vaapi: + case Encoder::h264_nvenc: + case Encoder::h264_software: + return kasmVideoH264; + default: + assert(false); + } + } + + static int32_t to_streaming_mode(Encoder encoder) { + switch (encoder) { + case Encoder::av1_vaapi: + case Encoder::av1_ffmpeg_vaapi: + case Encoder::av1_nvenc: + case Encoder::av1_software: + return pseudoEncodingStreamingModeAV1; + case Encoder::h265_vaapi: // h265 + case Encoder::h265_ffmpeg_vaapi: + case Encoder::h265_nvenc: + case Encoder::h265_software: + return pseudoEncodingStreamingModeHEVC; + case Encoder::h264_vaapi: + case Encoder::h264_ffmpeg_vaapi: + case Encoder::h264_nvenc: + case Encoder::h264_software: + return pseudoEncodingStreamingModeAVC; + default: + return pseudoEncodingStreamingModeJpegWebp; + } + } }; struct SupportedVideoEncoders { enum class Codecs : uint8_t { - H264, - H265, - AV1 + h264, + h264_vaapi, + h264_nvenc, + avc, + avc_vaapi, + avc_nvenc, + + h265, + h265_vaapi, + h265_nvenc, + hevc, + hevc_vaapi, + hevc_nvenc, + + av1, + av1_vaapi, + av1_nvenc, + auto_detect, + unavailable }; - static inline std::array CodecNames = {"h264", "h265", "av1"}; + static constexpr auto MappedCodecs = std::to_array({KasmVideoEncoders::Encoder::h264_software, + KasmVideoEncoders::Encoder::h264_ffmpeg_vaapi, + KasmVideoEncoders::Encoder::h264_nvenc, + KasmVideoEncoders::Encoder::h264_software, + KasmVideoEncoders::Encoder::h264_ffmpeg_vaapi, + KasmVideoEncoders::Encoder::h264_nvenc, + + KasmVideoEncoders::Encoder::h265_software, + KasmVideoEncoders::Encoder::h265_ffmpeg_vaapi, + KasmVideoEncoders::Encoder::h265_nvenc, + KasmVideoEncoders::Encoder::h265_software, + KasmVideoEncoders::Encoder::h265_ffmpeg_vaapi, + KasmVideoEncoders::Encoder::h265_nvenc, + + KasmVideoEncoders::Encoder::av1_software, + KasmVideoEncoders::Encoder::av1_ffmpeg_vaapi, + KasmVideoEncoders::Encoder::av1_nvenc, + KasmVideoEncoders::Encoder::h264_software, + KasmVideoEncoders::Encoder::unavailable}); + + static inline auto CodecNames = std::to_array({"h264", + "h264_vaapi", + "h264_nvenc", + "avc", + "avc_vaapi", + "avc_nvenc", + + "h265", + "h265_vaapi", + "h265_nvenc", + "hevc", + "hevc_vaapi", + "hevc_nvenc", + + "av1", + "av1_vaapi", + "av1_nvenc", + "auto"}); static std::string_view to_string(Codecs codec) { return CodecNames[static_cast(codec)]; @@ -53,38 +293,96 @@ namespace rfb { if (codec.empty()) return false; - for (auto supported_codec: CodecNames) + for (const auto supported_codec: CodecNames) if (supported_codec == codec) return true; - if (codec == "hevc") - return true; - return false; } - }; - struct KasmVideoEncoders { - enum class Encoder : uint8_t - { - av1_vaapi, - av1_software, - hevc_vaapi, // h265 - h265_software, - h264_vaapi, - h264_ffmpeg_vaapi, - h264_nvenc, - h264_software, - unavailable - }; + static auto get_codec(std::string_view codec) { + for (auto codec_impl: enum_range(Codecs::h264, Codecs::auto_detect)) { + if (to_string(codec_impl) == codec) + return codec_impl; + } - static inline std::array EncoderNames = { - "av1_vaapi", "av1_software", "hevc_vaapi", "libx265", "h264_vaapi", "h264_vaapi", "h264_nvenc", "libx264", "unavailable"}; + return Codecs::unavailable; + } - static std::string_view to_string(Encoder encoder) { - return EncoderNames[static_cast(encoder)]; + static constexpr auto map_encoder(Codecs impl) { + return MappedCodecs[static_cast(impl)]; + } + + static std::vector parse(std::string_view codecs) { + std::vector result; + + if (codecs.empty()) + return {}; + + size_t pos{}; + size_t start{}; + + while (pos < codecs.size()) { + pos = codecs.find_first_of(',', pos); + if (pos == std::string_view::npos) + pos = codecs.size(); + + result.push_back(codecs.substr(start, pos - start)); + + start = ++pos; + } + + return result; + } + + static KasmVideoEncoders::Encoders map_encoders(const std::vector &codecs) { + KasmVideoEncoders::Encoders result; + + if (codecs.empty()) + return {}; + + for (auto codec_name: codecs) { + const auto codec = get_codec(codec_name); + + switch (codec) { + case Codecs::auto_detect: + if (!result.empty()) + result.clear(); + + result.push_back(map_encoder(Codecs::av1_nvenc)); + result.push_back(map_encoder(Codecs::av1_vaapi)); + result.push_back(map_encoder(Codecs::av1)); + result.push_back(map_encoder(Codecs::h265_nvenc)); + result.push_back(map_encoder(Codecs::h265_vaapi)); + result.push_back(map_encoder(Codecs::h265)); + result.push_back(map_encoder(Codecs::h264_nvenc)); + result.push_back(map_encoder(Codecs::h264_vaapi)); + result.push_back(map_encoder(Codecs::h264)); + + return result; + default: + { + const auto encoder = map_encoder(codec); + if (std::find(result.begin(), result.end(), encoder) == result.end()) + result.push_back(encoder); + } + } + } + + return result; + } + + static KasmVideoEncoders::Encoders filter_available_encoders( + const KasmVideoEncoders::Encoders &encoders, const KasmVideoEncoders::Encoders &available) { + KasmVideoEncoders::Encoders result; + + for (auto encoder: available) { + if (std::ranges::find(encoders.begin(), encoders.end(), encoder) != encoders.end()) + result.push_back(encoder); + } + + return result; } }; - } // namespace rfb diff --git a/common/rfb/encoders/ScreenEncoderManager.cxx b/common/rfb/encoders/ScreenEncoderManager.cxx index 158fede..379d164 100644 --- a/common/rfb/encoders/ScreenEncoderManager.cxx +++ b/common/rfb/encoders/ScreenEncoderManager.cxx @@ -6,15 +6,21 @@ #include "rfb/encodings.h" namespace rfb { - ScreenEncoderManager::ScreenEncoderManager(const FFmpeg &ffmpeg_, KasmVideoEncoders::Encoder encoder, + template + ScreenEncoderManager::ScreenEncoderManager(const FFmpeg &ffmpeg_, KasmVideoEncoders::Encoder encoder, const std::vector &encoders, SConnection *conn, VideoEncoderParams params) : Encoder(conn, encodingKasmVideo, static_cast(EncoderUseNativePF | EncoderLossy), -1), ffmpeg(ffmpeg_), current_params(params), base_video_encoder(encoder), available_encoders(encoders) {} - ScreenEncoderManager::~ScreenEncoderManager() = default; + template + ScreenEncoderManager::~ScreenEncoderManager() { + for (uint8_t i = 0; i < get_screen_count(); ++i) + remove_screen(i); + }; - Encoder *ScreenEncoderManager::add_screen(const Screen &layout) const { + template + Encoder *ScreenEncoderManager::add_encoder(const Screen &layout) const { Encoder *encoder{}; try { encoder = create_encoder(layout, &ffmpeg, conn, base_video_encoder, current_params); @@ -33,63 +39,65 @@ namespace rfb { return encoder; } - size_t ScreenEncoderManager::get_screen_count() const { - return encoders.size(); + template + void ScreenEncoderManager::add_screen(uint8_t index, const Screen &layout) { + printf("SCREEN ADDED: %d (%d, %d, %d, %d)\n", index, layout.dimensions.tl.x, layout.dimensions.tl.y, layout.dimensions.br.x, layout.dimensions.br.y); + auto *encoder = add_encoder(layout); + assert(encoder); + screens[index] = {layout, encoder}; + head = std::min(head, index); + tail = std::max(tail, index); } - void ScreenEncoderManager::remove_screen(Encoder *encoder) { - std::erase(encoders, encoder); + template + size_t ScreenEncoderManager::get_screen_count() const { + return std::max(0, tail - head + 1); } - Encoder *ScreenEncoderManager::get_screen(size_t idx) const { - assert(idx < encoders.size()); - return encoders[idx]; - } - VideoEncoder *ScreenEncoderManager::get_video_encoder(size_t index) const { - assert(index < encoders.size()); - return reinterpret_cast(encoders[index]); - } - - void ScreenEncoderManager::sync_layout(const ScreenSet &layout) { - const auto new_count = layout.num_screens(); - const auto current_count = static_cast(encoders.size()); - const auto min_count = std::min(new_count, current_count); - - for (size_t i = 0; i < min_count; ++i) { - auto *encoder = encoders[i]; - if (!encoder || layout.screens[i].id != encoder->getId()) { - delete encoders[i]; - encoders[i] = add_screen(layout.screens[i]); - } + template + void ScreenEncoderManager::remove_screen(uint8_t index) { + if (screens[index].encoder) { + delete screens[index].encoder; + screens[index].encoder = nullptr; } + screens[index].layout = {}; + } - if (new_count < current_count) { - encoders.erase(encoders.begin() + new_count, encoders.end()); - } else if (new_count > current_count) { - encoders.reserve(new_count); + template + void ScreenEncoderManager::sync_layout(const ScreenSet &layout) { + for (uint8_t i = 0; i < layout.num_screens(); ++i) { + const auto &screen = layout.screens[i]; + auto id = screen.id; + if (id > ScreenSet::MAX_SCREENS) { + assert("Wrong id"); + id = 0; + } - for (size_t i = current_count; i < new_count; ++i) { - encoders.emplace_back(add_screen(layout.screens[i])); + if (!screens[id].layout.dimensions.equals(screen.dimensions)) { + remove_screen(id); + add_screen(id, screen); } } } - bool ScreenEncoderManager::isSupported() { - auto *base_encoder = encoders.front(); - assert(!base_encoder); - return base_encoder->isSupported(); + template + bool ScreenEncoderManager::isSupported() const { + if (const auto *encoder = screens[head].encoder; encoder) + return encoder->isSupported(); + + return false; } - void ScreenEncoderManager::writeRect(const PixelBuffer *pb, const Palette &palette) { - auto *base_encoder = encoders.front(); - assert(!base_encoder); - base_encoder->writeRect(pb, palette); + template + void ScreenEncoderManager::writeRect(const PixelBuffer *pb, const Palette &palette) { + if (auto *encoder = screens[head].encoder; encoder) + return encoder->writeRect(pb, palette); } - void ScreenEncoderManager::writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) { - auto *base_encoder = encoders.front(); - assert(!base_encoder); - base_encoder->writeSolidRect(width, height, pf, colour); + template + void ScreenEncoderManager::writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) { + if (auto *encoder = screens[head].encoder; encoder) + encoder->writeSolidRect(width, height, pf, colour); } } // namespace rfb diff --git a/common/rfb/encoders/ScreenEncoderManager.h b/common/rfb/encoders/ScreenEncoderManager.h index b06e67f..4f3292d 100644 --- a/common/rfb/encoders/ScreenEncoderManager.h +++ b/common/rfb/encoders/ScreenEncoderManager.h @@ -6,36 +6,45 @@ #include "rfb/ffmpeg.h" namespace rfb { + template class ScreenEncoderManager final : public Encoder { + struct screen_t { + Screen layout{}; + Encoder *encoder{}; + }; + + uint8_t head{}; + uint8_t tail{}; + + std::array screens{}; const FFmpeg &ffmpeg; VideoEncoderParams current_params; KasmVideoEncoders::Encoder base_video_encoder; std::vector available_encoders; - std::vector encoders; - Encoder *add_screen(const Screen &layout) const; + Encoder *add_encoder(const Screen &layout) const; + void add_screen(uint8_t index, const Screen &layout); [[nodiscard]] size_t get_screen_count() const; - void remove_screen(Encoder *encoder); - Encoder *get_screen(size_t screen_id) const; - VideoEncoder *get_video_encoder(size_t index) const; + void remove_screen(uint8_t index); public: - // Iterators - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; + // Iterator + using iterator = typename std::array::iterator; + using const_iterator = typename std::array::const_iterator; + iterator begin() { - return encoders.begin(); + return screens.begin(); } iterator end() { - return encoders.end(); + return screens.end(); } [[nodiscard]] const_iterator cbegin() const { - return encoders.begin(); + return screens.begin(); } [[nodiscard]] const_iterator cend() const { - return encoders.end(); + return screens.end(); } explicit ScreenEncoderManager(const FFmpeg &ffmpeg_, KasmVideoEncoders::Encoder encoder, @@ -50,10 +59,14 @@ namespace rfb { void sync_layout(const ScreenSet &layout); + KasmVideoEncoders::Encoder get_encoder() const { return base_video_encoder; } + // Encoder - bool isSupported() override; + bool isSupported() const override; void writeRect(const PixelBuffer *pb, const Palette &palette) override; void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override; }; + + template class ScreenEncoderManager<>; } // namespace rfb diff --git a/common/rfb/encoders/SoftwareEncoder.cxx b/common/rfb/encoders/SoftwareEncoder.cxx index 905ddb8..aad6c8e 100644 --- a/common/rfb/encoders/SoftwareEncoder.cxx +++ b/common/rfb/encoders/SoftwareEncoder.cxx @@ -4,22 +4,24 @@ extern "C" { #include } #include "KasmVideoConstants.h" -#include "rfb/LogWriter.h" -#include "rfb/SConnection.h" -#include "rfb/ServerCore.h" -#include "rfb/encodings.h" -#include "rfb/ffmpeg.h" +#include +#include +#include +#include +#include +#include -static rfb::LogWriter vlog("H264SoftwareEncoder"); +static rfb::LogWriter vlog("SoftwareEncoder"); namespace rfb { SoftwareEncoder::SoftwareEncoder(Screen layout_, const FFmpeg &ffmpeg_, SConnection *conn, KasmVideoEncoders::Encoder encoder_, VideoEncoderParams params) : Encoder(conn, encodingKasmVideo, static_cast(EncoderUseNativePF | EncoderLossy), -1), layout(layout_), - ffmpeg(ffmpeg_), encoder(encoder_), current_params(params) { - codec = ffmpeg.avcodec_find_encoder(AV_CODEC_ID_H264); + ffmpeg(ffmpeg_), encoder(encoder_), current_params(params), msg_codec_id(KasmVideoEncoders::to_msg_id(encoder)) { + const auto *enc_name = KasmVideoEncoders::to_string(encoder); + codec = ffmpeg.avcodec_find_encoder_by_name(enc_name); if (!codec) - throw std::runtime_error("Could not find H264 encoder"); + throw std::runtime_error(fmt::format("Could not find {} encoder", enc_name)); auto *frame = ffmpeg.av_frame_alloc(); if (!frame) { @@ -34,7 +36,7 @@ namespace rfb { pkt_guard.reset(pkt); } - bool SoftwareEncoder::isSupported() { + bool SoftwareEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingKasmVideo); } @@ -111,7 +113,8 @@ namespace rfb { vlog.debug("Key frame %ld", frame->pts); auto *os = conn->getOutStream(conn->cp.supportsUdp); - os->writeU8(kasmVideoH264 << 4); + os->writeU8(layout.id); + os->writeU8(msg_codec_id); os->writeU8(pkt->flags & AV_PKT_FLAG_KEY); write_compact(os, pkt->size); os->writeBytes(&pkt->data[0], pkt->size); diff --git a/common/rfb/encoders/SoftwareEncoder.h b/common/rfb/encoders/SoftwareEncoder.h index d56615c..f68591a 100644 --- a/common/rfb/encoders/SoftwareEncoder.h +++ b/common/rfb/encoders/SoftwareEncoder.h @@ -19,6 +19,7 @@ namespace rfb { KasmVideoEncoders::Encoder encoder; VideoEncoderParams current_params{}; + uint8_t msg_codec_id; int64_t pts{}; int bpp{}; @@ -30,7 +31,7 @@ namespace rfb { SoftwareEncoder(Screen layout, const FFmpeg &ffmpeg, SConnection *conn, KasmVideoEncoders::Encoder encoder, VideoEncoderParams params); public: - bool isSupported() override; + bool isSupported() const override; void writeRect(const PixelBuffer *pb, const Palette &palette) override; void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override; void writeSkipRect() override; diff --git a/common/rfb/encoders/VAAPIEncoder.cxx b/common/rfb/encoders/VAAPIEncoder.cxx index e204a17..ac50c75 100644 --- a/common/rfb/encoders/VAAPIEncoder.cxx +++ b/common/rfb/encoders/VAAPIEncoder.cxx @@ -259,7 +259,7 @@ namespace rfb { return true;*/ } - bool VAAPIEncoder::isSupported() { + bool VAAPIEncoder::isSupported() const { return conn->cp.supportsEncoding(encodingKasmVideo); } diff --git a/common/rfb/encoders/VAAPIEncoder.h b/common/rfb/encoders/VAAPIEncoder.h index addccdf..03e2a9f 100644 --- a/common/rfb/encoders/VAAPIEncoder.h +++ b/common/rfb/encoders/VAAPIEncoder.h @@ -62,7 +62,7 @@ namespace rfb { public: VAAPIEncoder(uint32_t id, SConnection *conn, uint8_t frame_rate, uint16_t bit_rate); - bool isSupported() override; + bool isSupported() const override; void writeRect(const PixelBuffer *pb, const Palette &palette) override; void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override; void writeSkipRect() override; diff --git a/common/rfb/encoders/VideoEncoderFactory.cxx b/common/rfb/encoders/VideoEncoderFactory.cxx index 8b5bf0a..fdb54fd 100644 --- a/common/rfb/encoders/VideoEncoderFactory.cxx +++ b/common/rfb/encoders/VideoEncoderFactory.cxx @@ -100,15 +100,23 @@ namespace rfb { VideoEncoderParams params) { switch (video_encoder) { case KasmVideoEncoders::Encoder::h264_vaapi: + case KasmVideoEncoders::Encoder::h265_vaapi: + case KasmVideoEncoders::Encoder::av1_vaapi: // return // H264VAAPIEncoderBuilder::create().with_connection(conn).with_frame_rate(frame_rate).with_bit_rate(bit_rate).build(); case KasmVideoEncoders::Encoder::h264_ffmpeg_vaapi: + case KasmVideoEncoders::Encoder::h265_ffmpeg_vaapi: + case KasmVideoEncoders::Encoder::av1_ffmpeg_vaapi: return FFMPEGVAAPIEncoderBuilder::create(ffmpeg) .with_layout(layout) .with_connection(conn) .with_encoder(video_encoder) .with_params(params) .build(); + case KasmVideoEncoders::Encoder::h264_nvenc: + case KasmVideoEncoders::Encoder::h265_nvenc: + case KasmVideoEncoders::Encoder::av1_nvenc: + throw std::runtime_error("NVENC is not supported yet"); default: return SoftwareEncoderBuilder::create(ffmpeg) .with_layout(layout) diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h index afb8208..d66f82a 100644 --- a/common/rfb/encodings.h +++ b/common/rfb/encodings.h @@ -21,80 +21,109 @@ namespace rfb { - const int encodingRaw = 0; - const int encodingCopyRect = 1; - const int encodingRRE = 2; - const int encodingCoRRE = 4; - const int encodingHextile = 5; - const int encodingTight = 7; - const int encodingUdp = 8; - const int encodingZRLE = 16; - const int encodingKasmVideo = 17; + constexpr int encodingRaw = 0; + constexpr int encodingCopyRect = 1; + constexpr int encodingRRE = 2; + constexpr int encodingCoRRE = 4; + constexpr int encodingHextile = 5; + constexpr int encodingTight = 7; + constexpr int encodingUdp = 8; + constexpr int encodingZRLE = 16; + constexpr int encodingKasmVideo = 17; - const int encodingMax = 255; + constexpr int encodingMax = 255; - const int pseudoEncodingXCursor = -240; - const int pseudoEncodingCursor = -239; - const int pseudoEncodingDesktopSize = -223; - const int pseudoEncodingLEDState = -261; - const int pseudoEncodingExtendedDesktopSize = -308; - const int pseudoEncodingDesktopName = -307; - const int pseudoEncodingFence = -312; - const int pseudoEncodingContinuousUpdates = -313; - const int pseudoEncodingCursorWithAlpha = -314; - const int pseudoEncodingQEMUKeyEvent = -258; + constexpr int pseudoEncodingXCursor = -240; + constexpr int pseudoEncodingCursor = -239; + constexpr int pseudoEncodingDesktopSize = -223; + constexpr int pseudoEncodingLEDState = -261; + constexpr int pseudoEncodingExtendedDesktopSize = -308; + constexpr int pseudoEncodingDesktopName = -307; + constexpr int pseudoEncodingFence = -312; + constexpr int pseudoEncodingContinuousUpdates = -313; + constexpr int pseudoEncodingCursorWithAlpha = -314; + constexpr int pseudoEncodingQEMUKeyEvent = -258; // TightVNC-specific - const int pseudoEncodingLastRect = -224; - const int pseudoEncodingQualityLevel0 = -32; - const int pseudoEncodingQualityLevel9 = -23; - const int pseudoEncodingCompressLevel0 = -256; - const int pseudoEncodingCompressLevel9 = -247; + constexpr int pseudoEncodingLastRect = -224; + constexpr int pseudoEncodingQualityLevel0 = -32; + constexpr int pseudoEncodingQualityLevel9 = -23; + constexpr int pseudoEncodingCompressLevel0 = -256; + constexpr int pseudoEncodingCompressLevel9 = -247; // TurboVNC-specific - const int pseudoEncodingFineQualityLevel0 = -512; - const int pseudoEncodingFineQualityLevel100 = -412; - const int pseudoEncodingSubsamp1X = -768; - const int pseudoEncodingSubsamp4X = -767; - const int pseudoEncodingSubsamp2X = -766; - const int pseudoEncodingSubsampGray = -765; - const int pseudoEncodingSubsamp8X = -764; - const int pseudoEncodingSubsamp16X = -763; + constexpr int pseudoEncodingFineQualityLevel0 = -512; + constexpr int pseudoEncodingFineQualityLevel100 = -412; + constexpr int pseudoEncodingSubsamp1X = -768; + constexpr int pseudoEncodingSubsamp4X = -767; + constexpr int pseudoEncodingSubsamp2X = -766; + constexpr int pseudoEncodingSubsampGray = -765; + constexpr int pseudoEncodingSubsamp8X = -764; + constexpr int pseudoEncodingSubsamp16X = -763; // Kasm-specific - const int pseudoEncodingWEBP = -1024; - const int pseudoEncodingJpegVideoQualityLevel0 = -1023; - const int pseudoEncodingJpegVideoQualityLevel9 = -1014; - const int pseudoEncodingWebpVideoQualityLevel0 = -1013; - const int pseudoEncodingWebpVideoQualityLevel9 = -1004; - const int pseudoEncodingTreatLosslessLevel0 = -1003; - const int pseudoEncodingTreatLosslessLevel10 = -993; - const int pseudoEncodingPreferBandwidth = -992; - const int pseudoEncodingDynamicQualityMinLevel0 = -991; - const int pseudoEncodingDynamicQualityMinLevel9 = -982; - const int pseudoEncodingDynamicQualityMaxLevel0 = -981; - const int pseudoEncodingDynamicQualityMaxLevel9 = -972; - const int pseudoEncodingVideoAreaLevel1 = -971; - const int pseudoEncodingVideoAreaLevel100 = -871; - const int pseudoEncodingVideoTimeLevel0 = -870; - const int pseudoEncodingVideoTimeLevel100 = -770; + constexpr int pseudoEncodingWEBP = -1024; + constexpr int pseudoEncodingJpegVideoQualityLevel0 = -1023; + constexpr int pseudoEncodingJpegVideoQualityLevel9 = -1014; + constexpr int pseudoEncodingWebpVideoQualityLevel0 = -1013; + constexpr int pseudoEncodingWebpVideoQualityLevel9 = -1004; + constexpr int pseudoEncodingTreatLosslessLevel0 = -1003; + constexpr int pseudoEncodingTreatLosslessLevel10 = -993; + constexpr int pseudoEncodingPreferBandwidth = -992; + constexpr int pseudoEncodingDynamicQualityMinLevel0 = -991; + constexpr int pseudoEncodingDynamicQualityMinLevel9 = -982; + constexpr int pseudoEncodingDynamicQualityMaxLevel0 = -981; + constexpr int pseudoEncodingDynamicQualityMaxLevel9 = -972; + constexpr int pseudoEncodingVideoAreaLevel1 = -971; + constexpr int pseudoEncodingVideoAreaLevel100 = -871; + constexpr int pseudoEncodingVideoTimeLevel0 = -870; + constexpr int pseudoEncodingVideoTimeLevel100 = -770; - const int pseudoEncodingFrameRateLevel10 = -2048; - const int pseudoEncodingFrameRateLevel60 = -1998; - const int pseudoEncodingMaxVideoResolution = -1997; - const int pseudoEncodingVideoScalingLevel0 = -1996; - const int pseudoEncodingVideoScalingLevel9 = -1987; - const int pseudoEncodingVideoOutTimeLevel1 = -1986; - const int pseudoEncodingVideoOutTimeLevel100 = -1887; - const int pseudoEncodingQOI = -1886; - const int pseudoEncodingKasmDisconnectNotify = -1885; + constexpr int pseudoEncodingFrameRateLevel10 = -2048; + constexpr int pseudoEncodingFrameRateLevel60 = -1998; + constexpr int pseudoEncodingMaxVideoResolution = -1997; + constexpr int pseudoEncodingVideoScalingLevel0 = -1996; + constexpr int pseudoEncodingVideoScalingLevel9 = -1987; + constexpr int pseudoEncodingVideoOutTimeLevel1 = -1986; + constexpr int pseudoEncodingVideoOutTimeLevel100 = -1887; + constexpr int pseudoEncodingQOI = -1886; + constexpr int pseudoEncodingKasmDisconnectNotify = -1885; + + constexpr int pseudoEncodingHardwareProfile0 = -1170; + constexpr int pseudoEncodingHardwareProfile4 = -1166; + + constexpr int pseudoEncodingGOP1 = -1165; + constexpr int pseudoEncodingGOP60 = -1105; + constexpr int pseudoEncodingStreamingVideoQualityLevel0 = -1104; + constexpr int pseudoEncodingStreamingVideoQualityLevel63 = -1041; + + // AV1 + constexpr int pseudoEncodingStreamingModeAV1QSV = -1040; + constexpr int pseudoEncodingStreamingModeAV1NVENC = -1039; + constexpr int pseudoEncodingStreamingModeAV1VAAPI = -1038; + constexpr int pseudoEncodingStreamingModeAV1SW = -1037; + constexpr int pseudoEncodingStreamingModeAV1 = -1036; + // h.265 + constexpr int pseudoEncodingStreamingModeHEVCQSV = -1035; + constexpr int pseudoEncodingStreamingModeHEVCNVENC = -1034; + constexpr int pseudoEncodingStreamingModeHEVCVAAPI = -1033; + constexpr int pseudoEncodingStreamingModeHEVCSW = -1032; + constexpr int pseudoEncodingStreamingModeHEVC = -1031; + // h.264 + constexpr int pseudoEncodingStreamingModeAVCQSV = -1030; + constexpr int pseudoEncodingStreamingModeAVCNVENC = -1029; + constexpr int pseudoEncodingStreamingModeAVCVAAPI = -1028; + constexpr int pseudoEncodingStreamingModeAVCSW = -1027; + constexpr int pseudoEncodingStreamingModeAVC = -1026; + + constexpr int pseudoEncodingStreamingModeJpegWebp = -1025; // VMware-specific - const int pseudoEncodingVMwareCursor = 0x574d5664; - const int pseudoEncodingVMwareCursorPosition = 0x574d5666; + constexpr int pseudoEncodingVMwareCursor = 0x574d5664; + constexpr int pseudoEncodingVMwareCursorPosition = 0x574d5666; // UltraVNC-specific - const int pseudoEncodingExtendedClipboard = 0xC0A1E5CE; + constexpr int pseudoEncodingExtendedClipboard = 0xC0A1E5CE; int encodingNum(const char* name); const char* encodingName(int num); diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h index e3932ad..d06625d 100644 --- a/common/rfb/msgTypes.h +++ b/common/rfb/msgTypes.h @@ -21,57 +21,58 @@ namespace rfb { // server to client - const int msgTypeFramebufferUpdate = 0; - const int msgTypeSetColourMapEntries = 1; - const int msgTypeBell = 2; - const int msgTypeServerCutText = 3; + constexpr int msgTypeFramebufferUpdate = 0; + constexpr int msgTypeSetColourMapEntries = 1; + constexpr int msgTypeBell = 2; + constexpr int msgTypeServerCutText = 3; - const int msgTypeEndOfContinuousUpdates = 150; + constexpr int msgTypeEndOfContinuousUpdates = 150; // kasm - const int msgTypeStats = 178; - const int msgTypeRequestFrameStats = 179; - const int msgTypeBinaryClipboard = 180; - const int msgTypeUpgradeToUdp = 181; - const int msgTypeSubscribeUnixRelay = 182; - const int msgTypeUnixRelay = 183; - const int msgTypeKeepAlive = 184; - const int msgTypeServerDisconnect = 185; - - const int msgTypeServerFence = 248; - const int msgTypeUserAddedToSession = 253; - const int msgTypeUserRemovedFromSession = 254; + constexpr int msgTypeStats = 178; + constexpr int msgTypeRequestFrameStats = 179; + constexpr int msgTypeBinaryClipboard = 180; + constexpr int msgTypeUpgradeToUdp = 181; + constexpr int msgTypeSubscribeUnixRelay = 182; + constexpr int msgTypeUnixRelay = 183; + constexpr int msgTypeVideoEncoders = 184; + constexpr int msgTypeKeepAlive = 185; + constexpr int msgTypeServerDisconnect = 186; + constexpr int msgTypeServerFence = 248; + constexpr int msgTypeUserAddedToSession = 253; + constexpr int msgTypeUserRemovedFromSession = 254; // client to server - const int msgTypeSetPixelFormat = 0; - const int msgTypeFixColourMapEntries = 1; - const int msgTypeSetEncodings = 2; - const int msgTypeFramebufferUpdateRequest = 3; - const int msgTypeKeyEvent = 4; - const int msgTypePointerEvent = 5; - const int msgTypeClientCutText = 6; + constexpr int msgTypeSetPixelFormat = 0; + constexpr int msgTypeFixColourMapEntries = 1; + constexpr int msgTypeSetEncodings = 2; + constexpr int msgTypeFramebufferUpdateRequest = 3; + constexpr int msgTypeKeyEvent = 4; + constexpr int msgTypePointerEvent = 5; + constexpr int msgTypeClientCutText = 6; - const int msgTypeEnableContinuousUpdates = 150; + constexpr int msgTypeEnableContinuousUpdates = 150; // kasm - const int msgTypeRequestStats = 178; - const int msgTypeFrameStats = 179; + constexpr int msgTypeRequestStats = 178; + constexpr int msgTypeFrameStats = 179; // same as the other direction - //const int msgTypeBinaryClipboard = 180; - //const int msgTypeUpgradeToUdp = 181; - //const int msgTypeSubscribeUnixRelay = 182; - //const int msgTypeUnixRelay = 183; - //const int msgTypeKeepAlive = 184; - //const int msgTypeServerDisconnect = 185; + //constexpr int msgTypeBinaryClipboard = 180; + //constexpr int msgTypeUpgradeToUdp = 181; + //constexpr int msgTypeSubscribeUnixRelay = 182; + //constexpr int msgTypeUnixRelay = 183; + //constexpr int msgTypeVideoEncoders = 184; + //constexpr int msgTypeKeepAlive = 185; + //constexpr int msgTypeServerDisconnect = 186; - const int msgTypeClientFence = 248; + constexpr int msgTypeClientFence = 248; - const int msgTypeSetDesktopSize = 251; + constexpr int msgTypeSetDesktopSize = 251; - const int msgTypeSetMaxVideoResolution = 252; + constexpr int msgTypeSetMaxVideoResolution = 252; - const int msgTypeQEMUClientMessage = 255; + constexpr int msgTypeQEMUClientMessage = 255; } #endif