mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2026-07-17 16:36:49 +00:00
VNC-151 Build fixes
This commit is contained in:
parent
37e26e3c6e
commit
2caa285168
8 changed files with 58 additions and 334 deletions
|
|
@ -68,7 +68,8 @@ RUN \
|
|||
xorg-server-common \
|
||||
xorg-server-dev \
|
||||
xtrans \
|
||||
ffmpeg-dev
|
||||
ffmpeg-dev \
|
||||
libva-dev
|
||||
|
||||
|
||||
ENV SCRIPTS_DIR=/tmp/scripts
|
||||
|
|
|
|||
|
|
@ -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
|
||||
"${source_dir}"/build-cpuid
|
||||
"${source_dir}"/build-fmt
|
||||
26
builder/scripts/build-fmt
Executable file
26
builder/scripts/build-fmt
Executable file
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 <unistd.h>
|
||||
#include <rdr/OutStream.h>
|
||||
#include <rfb/encodings.h>
|
||||
#include <rfb/LogWriter.h>
|
||||
#include <rfb/SConnection.h>
|
||||
#include <rfb/ServerCore.h>
|
||||
#include <rfb/PixelBuffer.h>
|
||||
#include <rfb/KasmVideoEncoder.h>
|
||||
#include <rfb/KasmVideoConstants.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/hwcontext_vaapi.h>
|
||||
}
|
||||
|
||||
|
||||
|
||||
using namespace rfb;
|
||||
static LogWriter vlog("KasmVideoEncoder");
|
||||
|
||||
|
||||
KasmVideoEncoder::KasmVideoEncoder(SConnection *conn) : Encoder(conn, encodingKasmVideo,
|
||||
static_cast<EncoderFlags>(
|
||||
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<int>(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<uint32_t>(pb->getRect().width()) || sh != static_cast<uint32_t>(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<const char *>(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
|
||||
}
|
||||
|
|
@ -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 <rfb/Encoder.h>
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -77,7 +77,8 @@
|
|||
#include <unistd.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
#include "KasmVideoConstants.h"
|
||||
#include <fmt/core.h>
|
||||
#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();
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <fcntl.h>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
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<uint8_t>(codec)];
|
||||
}
|
||||
};
|
||||
|
||||
struct KasmVideoEncoders {
|
||||
enum class Encoder : uint8_t
|
||||
{
|
||||
h264_vaapi,
|
||||
h264_nvenc,
|
||||
h264_software
|
||||
};
|
||||
|
||||
static inline std::array<std::string_view, 3> EncoderNames = {"h264_vaapi", "h264_nvenc", "libx264"};
|
||||
|
||||
static std::string_view to_string(Encoder encoder) {
|
||||
return EncoderNames[static_cast<uint8_t>(encoder)];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace rfb
|
||||
Loading…
Add table
Add a link
Reference in a new issue