From 2caa28516840aae66c535af71c751f821290bfcd Mon Sep 17 00:00:00 2001 From: El Date: Wed, 25 Jun 2025 04:14:03 +0500 Subject: [PATCH] VNC-151 Build fixes --- builder/dockerfile.alpine_321.build | 3 +- builder/scripts/build-deps.sh | 3 +- builder/scripts/build-fmt | 26 ++ common/rfb/CMakeLists.txt | 5 +- common/rfb/KasmVideoEncoder.cxx | 247 ------------------ common/rfb/KasmVideoEncoder.h | 61 ----- common/rfb/VNCServerST.cxx | 7 +- .../rfb/{ => encoders}/KasmVideoConstants.h | 40 +-- 8 files changed, 58 insertions(+), 334 deletions(-) create mode 100755 builder/scripts/build-fmt delete mode 100644 common/rfb/KasmVideoEncoder.cxx delete mode 100644 common/rfb/KasmVideoEncoder.h rename common/rfb/{ => encoders}/KasmVideoConstants.h (72%) diff --git a/builder/dockerfile.alpine_321.build b/builder/dockerfile.alpine_321.build index 80972ad..7d3b059 100644 --- a/builder/dockerfile.alpine_321.build +++ b/builder/dockerfile.alpine_321.build @@ -68,7 +68,8 @@ RUN \ xorg-server-common \ xorg-server-dev \ xtrans \ - ffmpeg-dev + ffmpeg-dev \ + libva-dev ENV SCRIPTS_DIR=/tmp/scripts diff --git a/builder/scripts/build-deps.sh b/builder/scripts/build-deps.sh index 5257861..da16ad5 100755 --- a/builder/scripts/build-deps.sh +++ b/builder/scripts/build-deps.sh @@ -6,4 +6,5 @@ source_dir=$(dirname "$0") "${source_dir}"/build-libjpeg-turbo "${source_dir}"/build-webp "${source_dir}"/build-tbb -"${source_dir}"/build-cpuid \ No newline at end of file +"${source_dir}"/build-cpuid +"${source_dir}"/build-fmt \ No newline at end of file diff --git a/builder/scripts/build-fmt b/builder/scripts/build-fmt new file mode 100755 index 0000000..f92eb13 --- /dev/null +++ b/builder/scripts/build-fmt @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +build_and_install() { + cmake -S . -B build -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -GNinja + ninja -C build install +} + +prepare_source() { + DIR=fmt + cd /tmp + [ -d ./${DIR} ] && rm -rf ./${DIR} + mkdir ${DIR} + + LIBCPUID_RELEASE=$(curl -sL "https://api.github.com/repos/fmtlib/fmt/releases/latest" \ + | grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') + + curl -Ls "https://github.com/fmtlib/fmt/archive/${LIBCPUID_RELEASE}.tar.gz" | \ + + tar xzvf - -C ${DIR}/ --strip-components=1 + cd ${DIR} +} + +prepare_source +build_and_install \ No newline at end of file diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index c9f5924..b0f0e4b 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -136,8 +136,9 @@ endif () find_package(PkgConfig REQUIRED) -pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil libswscale) +pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil libswscale libva) pkg_check_modules(CPUID REQUIRED libcpuid) +pkg_check_modules(FMT REQUIRED fmt) find_package(TBB) if (TBB_FOUND) @@ -160,7 +161,7 @@ target_include_directories(rfb PRIVATE ${CPUID_INCLUDE_DIRS} ) -target_link_libraries(rfb PUBLIC ${RFB_LIBRARIES} tinyxml2_objs ${TBB_LIBRARIES} ${CPUID_LIBRARIES}) +target_link_libraries(rfb PUBLIC ${RFB_LIBRARIES} tinyxml2_objs ${TBB_LIBRARIES} ${FFMPEG_LIBRARIES} ${CPUID_LIBRARIES} ${FMT_LIBRARIES}) if (UNIX) libtool_create_control_file(rfb) diff --git a/common/rfb/KasmVideoEncoder.cxx b/common/rfb/KasmVideoEncoder.cxx deleted file mode 100644 index b86a4a2..0000000 --- a/common/rfb/KasmVideoEncoder.cxx +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (C) 2024 Kasm. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -} - - - -using namespace rfb; -static LogWriter vlog("KasmVideoEncoder"); - - -KasmVideoEncoder::KasmVideoEncoder(SConnection *conn) : Encoder(conn, encodingKasmVideo, - static_cast( - EncoderUseNativePF | EncoderLossy), -1) { -} - -bool KasmVideoEncoder::isSupported() { - return conn->cp.supportsEncoding(encodingKasmVideo); -} - -bool init_codec(int w, int h, int fps, const AVCodec *codec, h264_t *h264) { - h264->frame = av_frame_alloc(); - if (!h264->frame) { - vlog.error("Can't allocate AVFrame"); - avcodec_free_context(&h264->ctx); - return false; - } - - h264->frame->format = hw_accel ? AV_PIX_FMT_VAAPI : AV_PIX_FMT_RGB24; - h264->frame->width = w; - h264->frame->height = h; - if (av_image_alloc(h264->frame->data, h264->frame->linesize, h264->frame->width, h264->frame->height, - AV_PIX_FMT_NV12, 32) < 0) { - vlog.error("Failed to allocate image"); - avcodec_free_context(&h264->ctx); - av_frame_free(&h264->frame); - return false; - } - - h264->ctx->width = w; - h264->ctx->height = h; - h264->ctx->time_base = (AVRational){1, static_cast(fps)}; - h264->ctx->gop_size = 10; - h264->ctx->max_b_frames = 0; - h264->ctx->pix_fmt = hw_accel ? AV_PIX_FMT_VAAPI : AV_PIX_FMT_YUV420P; - if (avcodec_open2(h264->ctx, codec, nullptr) < 0) { - vlog.error("Failed to open codec"); - avcodec_free_context(&h264->ctx); - av_frame_free(&h264->frame); - return false; - } - - return true; -} - -bool create_software_encoder(int width, int height, int fps, h264_t *h264) { - const auto *codec = avcodec_find_encoder(AV_CODEC_ID_H264); - h264->ctx = avcodec_alloc_context3(codec); - if (!h264->ctx) { - vlog.error("Can't allocate AVCodecContext"); - return false; - } - - if (!init_codec(width, height, fps, codec, h264)) - return false; - - return true; -} - -bool try_create_vaapi_encoder(int width, int height, int fps, h264_t *h264, AVBufferRef *hw_device_ctx) { - av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, render_path, nullptr, 0); - if (!hw_device_ctx) { - vlog.error("Failed to create VAAPI device context"); - return false; - } - - const auto *codec = avcodec_find_encoder_by_name("h264_vaapi"); - - h264->ctx = avcodec_alloc_context3(codec); - if (!h264->ctx) { - vlog.error("Can't allocate AVCodecContext"); - av_buffer_unref(&hw_device_ctx); - return false; - } - - h264->ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); - if (!h264->ctx->hw_device_ctx) { - vlog.error("Failed to reference VAAPI device context"); - avcodec_free_context(&h264->ctx); - av_buffer_unref(&hw_device_ctx); - return false; - } - - if (!init_codec(width, height, fps, codec, h264)) - return false; - - return true; -} - -static void init_h264(h264_t *h264, - const uint32_t w, const uint32_t h, const uint32_t fps, - const uint32_t bitrate) { - AVBufferRef *hw_device_ctx{}; - bool success{}; - if (!hw_accel) { - success = create_software_encoder(w, h, fps, h264); - } else { - success = try_create_vaapi_encoder(w, h, fps, h264, hw_device_ctx); - if (!success) { - hw_accel = false; - if (success = create_software_encoder(w, h, fps, h264); !success) { - vlog.error("Failed to create software encoder"); - return; - } - } - } - - if (!h264->ctx) { - vlog.error("Can't allocate AVFrame"); - avcodec_free_context(&h264->ctx); - } -} - -static void deinit_h264(h264_t *h264) { - if (h264->ctx && h264->ctx->hw_device_ctx) { - av_buffer_unref(&h264->ctx->hw_device_ctx); - } - avcodec_free_context(&h264->ctx); - av_frame_free(&h264->frame); -} - -void KasmVideoEncoder::writeRect(const PixelBuffer *pb, const Palette &palette) { - int stride; - const rdr::U8 *buffer = pb->getBuffer(pb->getRect(), &stride); - // compress - AVFrame *pFrame = av_frame_alloc(); - if (!pFrame) { - vlog.error("Can't allocate AVFrame"); - return; - } - - rdr::OutStream *os = conn->getOutStream(conn->cp.supportsUdp); - if (!strcmp(Server::videoCodec, "h264")) { - os->writeU8(kasmVideoH264 << 4); - if (!init) { - init_h264(&h264, pb->getRect().width(), pb->getRect().height(), Server::frameRate, - Server::videoBitrate); - init = true; - sw = pb->getRect().width(); - sh = pb->getRect().height(); - } else if (sw != static_cast(pb->getRect().width()) || sh != static_cast(pb->getRect(). - height())) { - deinit_h264(&h264); - init_h264(&h264, pb->getRect().width(), pb->getRect().height(), Server::frameRate, - Server::videoBitrate); - sw = pb->getRect().width(); - sh = pb->getRect().height(); - } - pFrame->format = hw_accel ? AV_PIX_FMT_VAAPI : AV_PIX_FMT_YUV420P; - pFrame->width = pb->getRect().width(); // Use the width from the PixelBuffer - pFrame->height = pb->getRect().height(); // Use the height from the PixelBuffer - if (av_image_fill_arrays(pFrame->data, pFrame->linesize, buffer, AV_PIX_FMT_BGR24, pb->getRect().width(), - pb->getRect().height(), 1) < 0) { - vlog.error("Can't fill image arrays"); - av_frame_free(&pFrame); - return; - } - int ret = avcodec_send_frame(h264.ctx, pFrame); - if (ret < 0) { - vlog.error("Error sending frame to codec"); - return; - } - while (ret >= 0) { - AVPacket pkt; - ret = avcodec_receive_packet(h264.ctx, &pkt); - if (ret < 0) { - vlog.error("Error receiving packet from codec"); - break; - } - writeCompact(pkt.size + 1, os); - os->writeBytes(&pkt.data[0], pkt.size); - av_packet_unref(&pkt); - } - } else { - vlog.error("Unknown test videoCodec %s", static_cast(Server::videoCodec)); - } - av_frame_free(&pFrame); -} - -void KasmVideoEncoder::writeSkipRect() { - auto *os = conn->getOutStream(conn->cp.supportsUdp); - os->writeU8(kasmVideoSkip << 4); -} - -void KasmVideoEncoder::writeCompact(rdr::U32 value, rdr::OutStream *os) { - // Copied from TightEncoder as it's overkill to inherit just for this - rdr::U8 b = value & 0x7F; - if (value <= 0x7F) { - os->writeU8(b); - } else { - os->writeU8(b | 0x80); - b = value >> 7 & 0x7F; - if (value <= 0x3FFF) { - os->writeU8(b); - } else { - os->writeU8(b | 0x80); - os->writeU8(value >> 14 & 0xFF); - } - } -} - -void KasmVideoEncoder::writeSolidRect(int width, int height, - const PixelFormat &pf, - const rdr::U8 *colour) { - // nop -} diff --git a/common/rfb/KasmVideoEncoder.h b/common/rfb/KasmVideoEncoder.h deleted file mode 100644 index 1a73196..0000000 --- a/common/rfb/KasmVideoEncoder.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2024 Kasm. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_KASMVIDEOENCODER_H__ -#define __RFB_KASMVIDEOENCODER_H__ - -#include -#include - -extern "C" { -#include -} - -struct h264_t { - AVCodecContext *ctx; - AVFrame *frame; - AVPacket pkt; -}; - -namespace rfb { - class KasmVideoEncoder : public Encoder { - public: - explicit KasmVideoEncoder(SConnection *conn); - - ~KasmVideoEncoder() override = default; - - bool isSupported() override; - - void writeRect(const PixelBuffer *pb, const Palette &palette) override; - - virtual void writeSkipRect(); - - void writeSolidRect(int width, int height, - const PixelFormat &pf, - const rdr::U8 *colour) override; - - protected: - static void writeCompact(rdr::U32 value, rdr::OutStream *os); - - private: - bool init{false}; - uint32_t sw{0}, sh{0}; - - h264_t h264{}; - }; -} -#endif diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 45187cf..cedb2f0 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -77,7 +77,8 @@ #include #include -#include "KasmVideoConstants.h" +#include +#include "encoders/KasmVideoConstants.h" using namespace rfb; @@ -239,8 +240,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) if (watermarkData) sendWatermark = true; - if (VideoEncoders::to_string(VideoEncoders::Codecs::H264) != Server::videoCodec.getValueStr()) - throw std::invalid_argument(std::format("Unknown test videoCodec {}", Server::videoCodec.getValueStr())); + if (SupportedVideoEncoders::to_string(SupportedVideoEncoders::Codecs::H264) != Server::videoCodec.getValueStr()) + throw std::invalid_argument(fmt::format("Unknown test videoCodec {}", Server::videoCodec.getValueStr())); if (Server::selfBench) SelfBench(); diff --git a/common/rfb/KasmVideoConstants.h b/common/rfb/encoders/KasmVideoConstants.h similarity index 72% rename from common/rfb/KasmVideoConstants.h rename to common/rfb/encoders/KasmVideoConstants.h index 03ce94a..ee2d900 100644 --- a/common/rfb/KasmVideoConstants.h +++ b/common/rfb/encoders/KasmVideoConstants.h @@ -17,9 +17,9 @@ */ #pragma once -#include #include -#include +#include +#include namespace rfb { // Compression control @@ -28,24 +28,9 @@ namespace rfb { static constexpr int GroupOfPictureSize = 10; // interval between I-frames - static auto render_path = "/dev/dri/renderD128"; + inline const char *render_path = "/dev/dri/renderD128"; - inline bool is_acceleration_available() { - if (access(render_path, R_OK | W_OK) != 0) - return false; - - const int fd = open(render_path, O_RDWR); - if (fd < 0) - return false; - - close(fd); - - return true; - } - - inline static bool hw_accel = is_acceleration_available(); - - struct VideoEncoders { + struct SupportedVideoEncoders { enum class Codecs : uint8_t { H264 @@ -57,4 +42,21 @@ namespace rfb { return CodecNames[static_cast(codec)]; } }; + + struct KasmVideoEncoders { + enum class Encoder : uint8_t + { + h264_vaapi, + h264_nvenc, + h264_software + }; + + static inline std::array EncoderNames = {"h264_vaapi", "h264_nvenc", "libx264"}; + + static std::string_view to_string(Encoder encoder) { + return EncoderNames[static_cast(encoder)]; + } + }; + + } // namespace rfb