Add native self-hosted instance connection to fluxer_desktop

Trimmed monorepo checkout (fluxer_desktop + packages/voice_engine_v2 +
tools/ci) with a "Connect to a Different Server" menu item and popout
that lets the desktop app switch to any self-hosted Fluxer instance,
plus fixes for well-known discovery on single-domain self-hosted
deployments and a false-positive ERR_ABORTED on same-origin client
redirects during the switch. Defaults to chat.fluxr.chat and uses an
isolated userData directory from the official build.
This commit is contained in:
2026-07-01 18:22:43 -04:00
commit 682afacd30
1763 changed files with 613720 additions and 0 deletions
@@ -0,0 +1,315 @@
#include "h264_encoder_impl.h"
#include <algorithm>
#include <limits>
#include <string>
#include "absl/strings/match.h"
#include "absl/types/optional.h"
#include "api/video/video_codec_constants.h"
#include "api/video_codecs/scalability_mode.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/include/video_error_codes.h"
#include "modules/video_coding/svc/create_scalability_structure.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
#include "modules/video_coding/utility/simulcast_utility.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/time_utils.h"
#include "system_wrappers/include/metrics.h"
#include "third_party/libyuv/include/libyuv/convert.h"
#include "third_party/libyuv/include/libyuv/scale.h"
#define VA_FOURCC_I420 0x30323449 // I420
namespace webrtc {
// Used by histograms. Values of entries should not be changed.
enum H264EncoderImplEvent {
kH264EncoderEventInit = 0,
kH264EncoderEventError = 1,
kH264EncoderEventMax = 16,
};
VAAPIH264EncoderWrapper::VAAPIH264EncoderWrapper(const webrtc::Environment& env,
const SdpVideoFormat& format)
: env_(env),
encoder_(new livekit_ffi::VaapiH264EncoderWrapper()),
packetization_mode_(
H264EncoderSettings::Parse(format).packetization_mode),
format_(format) {
std::string hexString = format_.parameters.at("profile-level-id");
std::optional<webrtc::H264ProfileLevelId> profile_level_id =
webrtc::ParseH264ProfileLevelId(hexString.c_str());
if (profile_level_id.has_value()) {
profile_ = profile_level_id->profile;
level_ = profile_level_id->level;
}
}
VAProfile VAAPIH264EncoderWrapper::GetVAProfile() const {
switch (profile_) {
case H264Profile::kProfileConstrainedBaseline:
case H264Profile::kProfileBaseline:
return VAProfileH264ConstrainedBaseline;
case H264Profile::kProfileMain:
return VAProfileH264Main;
case H264Profile::kProfileConstrainedHigh:
case H264Profile::kProfileHigh:
return VAProfileH264High;
}
return VAProfileNone;
}
VAAPIH264EncoderWrapper::~VAAPIH264EncoderWrapper() {
Release();
}
void VAAPIH264EncoderWrapper::ReportInit() {
if (has_reported_init_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264EncoderImpl.Event",
kH264EncoderEventInit, kH264EncoderEventMax);
has_reported_init_ = true;
}
void VAAPIH264EncoderWrapper::ReportError() {
if (has_reported_error_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264EncoderImpl.Event",
kH264EncoderEventError, kH264EncoderEventMax);
has_reported_error_ = true;
}
int32_t VAAPIH264EncoderWrapper::InitEncode(
const VideoCodec* inst,
const VideoEncoder::Settings& settings) {
if (!inst || inst->codecType != kVideoCodecH264) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (inst->maxFramerate == 0) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (inst->width < 1 || inst->height < 1) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
int32_t release_ret = Release();
if (release_ret != WEBRTC_VIDEO_CODEC_OK) {
ReportError();
return release_ret;
}
codec_ = *inst;
// Code expects simulcastStream resolutions to be correct, make sure they are
// filled even when there are no simulcast layers.
if (codec_.numberOfSimulcastStreams == 0) {
codec_.simulcastStream[0].width = codec_.width;
codec_.simulcastStream[0].height = codec_.height;
}
// Initialize encoded image. Default buffer size: size of unencoded data.
const size_t new_capacity =
CalcBufferSize(VideoType::kI420, codec_.width, codec_.height);
encoded_image_.SetEncodedData(EncodedImageBuffer::Create(new_capacity));
encoded_image_._encodedWidth = codec_.width;
encoded_image_._encodedHeight = codec_.height;
encoded_image_.set_size(0);
configuration_.sending = false;
configuration_.frame_dropping_on = codec_.GetFrameDropEnabled();
configuration_.key_frame_interval = codec_.H264()->keyFrameInterval;
configuration_.width = codec_.width;
configuration_.height = codec_.height;
configuration_.max_frame_rate = codec_.maxFramerate;
configuration_.target_bps = codec_.startBitrate * 1000;
configuration_.max_bps = codec_.maxBitrate * 1000;
if (!encoder_->IsInitialized()) {
// Initialize encoder.
int keyFrameInterval = 60;
if (codec_.maxFramerate > 0) {
keyFrameInterval = codec_.maxFramerate * 5;
}
auto va_profile = GetVAProfile();
if (va_profile == VAProfileNone) {
RTC_LOG(LS_ERROR) << "Unsupported H264 profile: "
<< static_cast<int>(profile_);
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
encoder_->Initialize(codec_.width, codec_.height,
codec_.startBitrate * 1000, keyFrameInterval,
keyFrameInterval, 1, codec_.maxFramerate,
va_profile, VA_RC_CBR);
}
SimulcastRateAllocator init_allocator(env_, codec_);
VideoBitrateAllocation allocation =
init_allocator.Allocate(VideoBitrateAllocationParameters(
DataRate::KilobitsPerSec(codec_.startBitrate), codec_.maxFramerate));
SetRates(RateControlParameters(allocation, codec_.maxFramerate));
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t VAAPIH264EncoderWrapper::RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) {
encoded_image_callback_ = callback;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t VAAPIH264EncoderWrapper::Release() {
if (encoder_->IsInitialized()) {
encoder_->Destroy();
}
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t VAAPIH264EncoderWrapper::Encode(
const VideoFrame& input_frame,
const std::vector<VideoFrameType>* frame_types) {
if (!encoder_) {
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (!encoded_image_callback_) {
RTC_LOG(LS_WARNING)
<< "InitEncode() has been called, but a callback function "
"has not been set with RegisterEncodeCompleteCallback()";
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
webrtc::scoped_refptr<I420BufferInterface> frame_buffer =
input_frame.video_frame_buffer()->ToI420();
if (!frame_buffer) {
RTC_LOG(LS_ERROR) << "Failed to convert "
<< VideoFrameBufferTypeToString(
input_frame.video_frame_buffer()->type())
<< " image to I420. Can't encode frame.";
return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
}
RTC_CHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 ||
frame_buffer->type() == VideoFrameBuffer::Type::kI420A);
bool is_keyframe_needed = false;
if (configuration_.key_frame_request && configuration_.sending) {
is_keyframe_needed = true;
}
bool send_key_frame =
is_keyframe_needed ||
(frame_types && (*frame_types)[0] == VideoFrameType::kVideoFrameKey);
if (send_key_frame) {
is_keyframe_needed = true;
configuration_.key_frame_request = false;
}
RTC_DCHECK_EQ(configuration_.width, frame_buffer->width());
RTC_DCHECK_EQ(configuration_.height, frame_buffer->height());
if (!configuration_.sending) {
return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
}
if (frame_types != nullptr) {
// Skip frame?
if ((*frame_types)[0] == VideoFrameType::kEmptyFrame) {
return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
}
}
std::vector<uint8_t> output;
encoder_->Encode(VA_FOURCC_I420, frame_buffer->DataY(), frame_buffer->DataU(),
frame_buffer->DataV(), send_key_frame, output);
if (output.empty()) {
RTC_LOG(LS_ERROR) << "Failed to encode frame.";
return WEBRTC_VIDEO_CODEC_ERROR;
}
encoded_image_.SetEncodedData(
EncodedImageBuffer::Create(output.data(), output.size()));
h264_bitstream_parser_.ParseBitstream(encoded_image_);
encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1);
encoded_image_._encodedWidth = configuration_.width;
encoded_image_._encodedHeight = configuration_.height;
encoded_image_.SetRtpTimestamp(input_frame.rtp_timestamp());
encoded_image_.SetColorSpace(input_frame.color_space());
encoded_image_._frameType = send_key_frame ? VideoFrameType::kVideoFrameKey
: VideoFrameType::kVideoFrameDelta;
CodecSpecificInfo codec_specific;
codec_specific.codecType = kVideoCodecH264;
codec_specific.codecSpecific.H264.packetization_mode = packetization_mode_;
codec_specific.codecSpecific.H264.temporal_idx = kNoTemporalIdx;
codec_specific.codecSpecific.H264.base_layer_sync = false;
codec_specific.codecSpecific.H264.idr_frame = send_key_frame;
encoded_image_callback_->OnEncodedImage(encoded_image_, &codec_specific);
return WEBRTC_VIDEO_CODEC_OK;
}
VideoEncoder::EncoderInfo VAAPIH264EncoderWrapper::GetEncoderInfo() const {
EncoderInfo info;
info.supports_native_handle = false;
info.implementation_name = "VAAPI H264 Encoder";
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
info.is_hardware_accelerated = true;
info.supports_simulcast = false;
info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420};
return info;
}
void VAAPIH264EncoderWrapper::SetRates(
const RateControlParameters& parameters) {
if (!encoder_) {
RTC_LOG(LS_WARNING) << "SetRates() while uninitialized.";
return;
}
if (parameters.framerate_fps < 1.0) {
RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps;
return;
}
if (parameters.bitrate.get_sum_bps() == 0) {
configuration_.SetStreamState(false);
return;
}
codec_.maxFramerate = static_cast<uint32_t>(parameters.framerate_fps);
configuration_.target_bps = parameters.bitrate.GetSpatialLayerSum(0);
configuration_.max_frame_rate = parameters.framerate_fps;
if (configuration_.target_bps) {
configuration_.SetStreamState(true);
// Update max_frame_rate/target_bitrate for vaapi encoder.
encoder_->UpdateRates(configuration_.max_frame_rate,
configuration_.target_bps);
} else {
configuration_.SetStreamState(false);
}
}
void VAAPIH264EncoderWrapper::LayerConfig::SetStreamState(bool send_stream) {
if (send_stream && !sending) {
// Need a key frame if we have not sent this stream before.
key_frame_request = true;
}
sending = send_stream;
}
} // namespace webrtc
@@ -0,0 +1,83 @@
#ifndef VAAPI_H264_ENCODER_IMPL_H_
#define VAAPI_H264_ENCODER_IMPL_H_
#include <memory>
#include <vector>
#include "absl/container/inlined_vector.h"
#include "api/transport/rtp/dependency_descriptor.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_codec_constants.h"
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_encoder.h"
#include "common_video/h264/h264_bitstream_parser.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "modules/video_coding/svc/scalable_video_controller.h"
#include "modules/video_coding/utility/quality_scaler.h"
#include "vaapi_h264_encoder_wrapper.h"
namespace webrtc {
class VAAPIH264EncoderWrapper : public VideoEncoder {
public:
struct LayerConfig {
int simulcast_idx = 0;
int width = -1;
int height = -1;
bool sending = true;
bool key_frame_request = false;
float max_frame_rate = 0;
uint32_t target_bps = 0;
uint32_t max_bps = 0;
bool frame_dropping_on = false;
int key_frame_interval = 0;
int num_temporal_layers = 1;
void SetStreamState(bool send_stream);
};
public:
VAAPIH264EncoderWrapper(const webrtc::Environment& env,
const SdpVideoFormat& format);
~VAAPIH264EncoderWrapper() override;
int32_t InitEncode(const VideoCodec* codec_settings,
const Settings& settings) override;
int32_t RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) override;
int32_t Release() override;
int32_t Encode(const VideoFrame& frame,
const std::vector<VideoFrameType>* frame_types) override;
void SetRates(const RateControlParameters& rc_parameters) override;
EncoderInfo GetEncoderInfo() const override;
private:
VAProfile GetVAProfile() const;
private:
const webrtc::Environment& env_;
EncodedImageCallback* encoded_image_callback_ = nullptr;
std::unique_ptr<livekit_ffi::VaapiH264EncoderWrapper> encoder_;
LayerConfig configuration_;
EncodedImage encoded_image_;
H264PacketizationMode packetization_mode_;
VideoCodec codec_;
void ReportInit();
void ReportError();
bool has_reported_init_ = false;
bool has_reported_error_ = false;
webrtc::H264BitstreamParser h264_bitstream_parser_;
const SdpVideoFormat format_;
H264Profile profile_ = H264Profile::kProfileConstrainedBaseline;
H264Level level_ = H264Level::kLevel1_b;
};
} // namespace webrtc
#endif // VAAPI_H264_ENCODER_IMPL_H_
@@ -0,0 +1,135 @@
#include "vaapi_display_drm.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef IN_LIBVA
#include "va/drm/va_drm.h"
#else
#include <va/va_drm.h>
#endif
#include "rtc_base/logging.h"
static bool check_h264_encoding_support(VADisplay va_display) {
VAProfile profile_list[] = {VAProfileH264High, VAProfileH264Main,
VAProfileH264ConstrainedBaseline};
VAProfile h264_profile = VAProfileH264ConstrainedBaseline;
VAEntrypoint* entrypoints;
int num_entrypoints, slice_entrypoint;
bool support_encode = false;
int selected_entrypoint = -1;
int major_ver, minor_ver;
VAStatus va_status;
uint32_t i;
if (!va_display) {
return false;
}
va_status = vaInitialize(va_display, &major_ver, &minor_ver);
if (major_ver < 0 || minor_ver < 0 || va_status != VA_STATUS_SUCCESS) {
RTC_LOG(LS_ERROR) << "vaInitialize failed";
return false;
}
num_entrypoints = vaMaxNumEntrypoints(va_display);
entrypoints = new VAEntrypoint[num_entrypoints * sizeof(*entrypoints)];
if (!entrypoints) {
RTC_LOG(LS_ERROR) << "failed to allocate VA entrypoints";
return false;
}
/* use the highest profile */
for (i = 0; i < sizeof(profile_list) / sizeof(profile_list[0]); i++) {
if ((h264_profile != ~0) && h264_profile != profile_list[i])
continue;
h264_profile = profile_list[i];
vaQueryConfigEntrypoints(va_display, h264_profile, entrypoints,
&num_entrypoints);
for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints;
slice_entrypoint++) {
if ((entrypoints[slice_entrypoint] == VAEntrypointEncSlice) ||
(entrypoints[slice_entrypoint] == VAEntrypointEncSliceLP)) {
support_encode = true;
selected_entrypoint = entrypoints[slice_entrypoint];
break;
}
}
if (support_encode) {
RTC_LOG(LS_INFO) << "Using EntryPoint - " << selected_entrypoint;
break;
}
}
if (support_encode) {
RTC_LOG(LS_INFO) << "Supported H264 Encoder, Using EntryPoint - "
<< selected_entrypoint;
} else {
RTC_LOG(LS_ERROR)
<< "Can't find VAEntrypointEncSlice or VAEntrypointEncSliceLP for "
"H264 profiles";
delete[] entrypoints;
return false;
}
delete[] entrypoints;
return true;
}
static VADisplay va_open_display_drm(int* drm_fd) {
VADisplay va_dpy;
int i;
static const char* drm_device_paths[] = {"/dev/dri/renderD128",
"/dev/dri/renderD129", NULL};
for (i = 0; drm_device_paths[i]; i++) {
*drm_fd = open(drm_device_paths[i], O_RDWR);
if (*drm_fd < 0)
continue;
va_dpy = vaGetDisplayDRM(*drm_fd);
vaSetErrorCallback(va_dpy, NULL, NULL);
vaSetInfoCallback(va_dpy, NULL, NULL);
if (va_dpy && check_h264_encoding_support(va_dpy))
return va_dpy;
close(*drm_fd);
*drm_fd = -1;
}
return NULL;
}
namespace livekit_ffi {
bool VaapiDisplayDrm::Open() {
va_display_ = va_open_display_drm(&drm_fd_);
if (!va_display_) {
RTC_LOG(LS_ERROR) << "Failed to open VA drm display. Maybe the AMD video "
"driver or libva-dev/libdrm-dev is not installed?";
return false;
}
return true;
}
bool VaapiDisplayDrm::isOpen() const {
return va_display_ != nullptr;
}
void VaapiDisplayDrm::Close() {
if (va_display_) {
if (drm_fd_ < 0)
return;
close(drm_fd_);
drm_fd_ = -1;
va_display_ = nullptr;
}
}
} // namespace livekit_ffi
@@ -0,0 +1,35 @@
#ifndef VAAPI_DISPLAY_DRM_H_
#define VAAPI_DISPLAY_DRM_H_
#include <stdio.h>
#include <va/va.h>
namespace livekit_ffi {
// VAAPI drm display wrapper class
class VaapiDisplayDrm {
public:
VaapiDisplayDrm() = default;
VaapiDisplayDrm(const VaapiDisplayDrm&) = delete;
~VaapiDisplayDrm() = default;
// Initialize the VAAPI display
bool Open();
// Check if the VAAPI display is open
bool isOpen() const;
// Close the VAAPI display
void Close();
// Get the VAAPI display handle
VADisplay display() const { return va_display_; }
private:
VADisplay va_display_;
int drm_fd_;
};
} // namespace livekit_ffi
#endif // VAAPI_DISPLAY_DRM_H_
@@ -0,0 +1,192 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "vaapi_display_win32.h"
#include <directx/dxcore_interface.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static const char* g_device_name;
void dxcore_resolve_adapter(const char* adapter_string,
/*out*/ bool* ptr_device_found,
/*out*/ LUID* ptr_adapter_luid) {
int selected_adapter_index = -1;
IDXCoreAdapterFactory* factory = nullptr;
IDXCoreAdapterList* adapter_list = nullptr;
IDXCoreAdapter* adapter = nullptr;
typedef HRESULT(WINAPI * PFN_CREATE_DXCORE_ADAPTER_FACTORY)(REFIID riid,
void** ppFactory);
PFN_CREATE_DXCORE_ADAPTER_FACTORY DXCoreCreateAdapterFactory;
HRESULT hr = S_OK;
memset(ptr_adapter_luid, 0, sizeof(LUID));
*ptr_device_found = false;
HMODULE dxcore_mod = LoadLibraryA("DXCore.DLL");
if (!dxcore_mod) {
fprintf(stderr, "Failed to load DXCore.DLL to enumerate adapters.\n");
goto fail;
}
DXCoreCreateAdapterFactory =
(PFN_CREATE_DXCORE_ADAPTER_FACTORY)GetProcAddress(
dxcore_mod, "DXCoreCreateAdapterFactory");
if (!DXCoreCreateAdapterFactory) {
fprintf(stderr,
"Failed to load DXCoreCreateAdapterFactory from DXCore.DLL.\n");
goto fail;
}
hr = DXCoreCreateAdapterFactory(IID_IDXCoreAdapterFactory, (void**)&factory);
if (FAILED(hr)) {
fprintf(stderr, "DXCoreCreateAdapterFactory failed: %lx\n", hr);
goto fail;
}
hr =
factory->CreateAdapterList(1, &DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS,
IID_IDXCoreAdapterList, (void**)&adapter_list);
if (FAILED(hr)) {
fprintf(stderr, "CreateAdapterList failed: %lx\n", hr);
goto fail;
}
if (adapter_string &&
(sscanf_s(adapter_string, "%d", &selected_adapter_index) != 1)) {
fprintf(stderr, "Invalid device index received for -hwaccel_device %s\n",
adapter_string ? adapter_string : "");
}
if (!adapter_string)
fprintf(stdout, "Available devices for --display win32:\n");
for (int i = 0; i < adapter_list->GetAdapterCount(); i++) {
if (SUCCEEDED(adapter_list->GetAdapter(i, IID_IDXCoreAdapter,
(void**)&adapter))) {
size_t desc_size = 0;
if (FAILED(adapter->GetPropertySize(
DXCoreAdapterProperty::DriverDescription, &desc_size))) {
adapter->Release();
continue;
}
char* adapter_name = (char*)malloc(desc_size);
if (!adapter_name) {
adapter->Release();
continue;
}
if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::DriverDescription,
desc_size, adapter_name))) {
free(adapter_name);
adapter->Release();
continue;
}
LUID cur_adapter_luid = {0, 0};
if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::InstanceLuid,
&cur_adapter_luid))) {
free(adapter_name);
adapter->Release();
continue;
}
if (selected_adapter_index == i) {
*ptr_adapter_luid = cur_adapter_luid;
*ptr_device_found = true;
}
if (!adapter_string)
fprintf(stdout,
"\tDevice Index: %d Device LUID: %lu %ld - Device Name: %s\n",
i, cur_adapter_luid.LowPart, cur_adapter_luid.HighPart,
adapter_name);
free(adapter_name);
adapter->Release();
}
}
fail:
if (adapter_list)
adapter_list->Release();
if (factory)
factory->Release();
if (dxcore_mod)
FreeLibrary(dxcore_mod);
}
static VADisplay va_open_display_win32(void) {
LUID adapter_luid = {0, 0};
bool device_found = false;
if (g_device_name) {
bool print_devices = (0 == strcmp(g_device_name, "help"));
dxcore_resolve_adapter(print_devices ? NULL : g_device_name, &device_found,
&adapter_luid);
if (print_devices) {
exit(0);
} else if (g_device_name && !device_found) {
fprintf(stderr,
"Could not find device %s for --display win32. Please try "
"--device help for a list of available devices.\n",
g_device_name);
exit(0);
}
}
// Adapter automatic selection supported by sending NULL adapter to
// vaGetDisplayWin32
return vaGetDisplayWin32(device_found ? &adapter_luid : NULL);
}
static void va_close_display_win32(VADisplay va_dpy) {}
namespace livekit_ffi {
VaapiDisplayWin32::VaapiDisplayWin32() : va_display_(nullptr) {
putenv("LIBVA_DRIVER_NAME=vaon12");
putenv("LIBVA_DRIVERS_PATH=.");
}
bool VaapiDisplayWin32::Open() {
va_display_ = va_open_display_win32();
if (!va_display_) {
fprintf(stderr, "Failed to open VA display\n");
return false;
}
return true;
}
bool VaapiDisplayWin32::isOpen() const {
return va_display_ != nullptr;
}
void VaapiDisplayWin32::Close() {
if (va_display_) {
va_close_display_win32(va_display_);
va_display_ = nullptr;
}
}
} // namespace livekit_ffi
@@ -0,0 +1,33 @@
#ifndef VAAPI_DISPLAY_WIN32_H_
#define VAAPI_DISPLAY_WIN32_H_
#include <va/va.h>
#include <va/va_win32.h>
namespace livekit_ffi {
// VAAPI win32 display wrapper class
class VaapiDisplayWin32 {
public:
VaapiDisplayWin32();
~VaapiDisplayWin32() {}
// Initialize the VAAPI display
bool Open();
// Check if the VAAPI display is open
bool isOpen() const;
// Close the VAAPI display
void Close();
// Get the VAAPI display handle
VADisplay display() const { return va_display_; }
private:
VADisplay va_display_ = nullptr;
};
} // namespace livekit_ffi
#endif // VAAPI_DISPLAY_WIN32_H_
@@ -0,0 +1,93 @@
#include "vaapi_encoder_factory.h"
#include <memory>
#include <iostream>
#include <dlfcn.h>
#include "h264_encoder_impl.h"
#include "rtc_base/logging.h"
#if defined(WIN32)
#include "vaapi_display_win32.h"
using VaapiDisplay = livekit_ffi::VaapiDisplayWin32;
#elif defined(__linux__)
#include "vaapi_display_drm.h"
using VaapiDisplay = livekit_ffi::VaapiDisplayDrm;
#endif
namespace webrtc {
VAAPIVideoEncoderFactory::VAAPIVideoEncoderFactory() {
std::map<std::string, std::string> baselineParameters = {
{"profile-level-id", "42e01f"},
{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
};
supported_formats_.push_back(SdpVideoFormat("H264", baselineParameters));
/*
std::map<std::string, std::string> highParameters = {
{"profile-level-id", "4d0032"},
{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
};
supported_formats_.push_back(SdpVideoFormat("H264", highParameters));
*/
}
VAAPIVideoEncoderFactory::~VAAPIVideoEncoderFactory() {}
bool VAAPIVideoEncoderFactory::IsSupported() {
// Ensure that libva and libva-drm are actually available for loading.
// Otherwise, we will immediately abort.
void* libva_ptr = dlopen("libva.so.2", RTLD_LAZY);
if (!libva_ptr) {
RTC_LOG(LS_INFO) << "libva.so.2 is not found";
return false;
}
dlclose(libva_ptr);
void* libvadrm_ptr = dlopen("libva-drm.so.2", RTLD_LAZY);
if (!libvadrm_ptr) {
RTC_LOG(LS_INFO) << "libva-drm.so.2 is not found";
return false;
}
dlclose(libvadrm_ptr);
// Check if VAAPI is supported by the environment.
// This could involve checking if the VAAPI display can be opened.
VaapiDisplay vaapi_display;
if (!vaapi_display.Open()) {
RTC_LOG(LS_WARNING) << "Failed to open VAAPI display.";
return false;
}
vaapi_display.Close();
// If we can open the VAAPI display, we consider it supported.
std::cout << "VAAPI is supported." << std::endl;
return true;
}
std::unique_ptr<VideoEncoder> VAAPIVideoEncoderFactory::Create(
const Environment& env,
const SdpVideoFormat& format) {
// Check if the requested format is supported.
for (const auto& supported_format : supported_formats_) {
if (format.IsSameCodec(supported_format)) {
// If the format is supported, create and return the encoder.
return std::make_unique<VAAPIH264EncoderWrapper>(env, format);
}
}
return nullptr;
}
std::vector<SdpVideoFormat> VAAPIVideoEncoderFactory::GetSupportedFormats()
const {
return supported_formats_;
}
std::vector<SdpVideoFormat> VAAPIVideoEncoderFactory::GetImplementations()
const {
return supported_formats_;
}
} // namespace webrtc
@@ -0,0 +1,40 @@
#ifndef VAAPI_VIDEO_ENCODER_FACTORY_H_
#define VAAPI_VIDEO_ENCODER_FACTORY_H_
#include <vector>
#include "api/environment/environment.h"
#include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_encoder_factory.h"
namespace webrtc {
class VAAPIVideoEncoderFactory : public VideoEncoderFactory {
public:
VAAPIVideoEncoderFactory();
~VAAPIVideoEncoderFactory() override;
static bool IsSupported();
std::unique_ptr<VideoEncoder> Create(const Environment& env,
const SdpVideoFormat& format) override;
// Returns a list of supported codecs in order of preference.
std::vector<SdpVideoFormat> GetSupportedFormats() const override;
std::vector<SdpVideoFormat> GetImplementations() const override;
std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override {
return nullptr;
}
private:
std::vector<SdpVideoFormat> supported_formats_;
};
} // namespace webrtc
#endif // VAAPI_VIDEO_ENCODER_FACTORY_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,127 @@
#ifndef VAAPI_H264_ENCODER_WRAPPER_H_
#define VAAPI_H264_ENCODER_WRAPPER_H_
#include <stdbool.h>
#include <stdint.h>
#include <va/va.h>
#include <va/va_enc_h264.h>
#include <memory>
#include <vector>
#if defined(WIN32)
#include "vaapi_display_win32.h"
using VaapiDisplay = livekit_ffi::VaapiDisplayWin32;
#elif defined(__linux__)
#include "vaapi_display_drm.h"
using VaapiDisplay = livekit_ffi::VaapiDisplayDrm ;
#endif
#define SURFACE_NUM 16 /* 16 surfaces for reference */
typedef struct {
// one of: VAProfileH264ConstrainedBaseline, VAProfileH264Main,
// VAProfileH264High
VAProfile h264_profile;
int h264_entropy_mode;
int frame_width;
int frame_height;
int frame_rate;
uint32_t bitrate;
int initial_qp;
int minimal_qp;
int intra_period;
int intra_idr_period;
int ip_period;
int rc_mode;
} VA264Config;
typedef struct {
VADisplay va_dpy;
VAConfigAttrib attrib[VAConfigAttribTypeMax];
VAConfigAttrib config_attrib[VAConfigAttribTypeMax];
int config_attrib_num;
int enc_packed_header_idx;
VASurfaceID src_surface[SURFACE_NUM];
VABufferID coded_buf[SURFACE_NUM];
VASurfaceID ref_surface[SURFACE_NUM];
VAConfigID config_id;
VAContextID context_id;
VAEncSequenceParameterBufferH264 seq_param;
VAEncPictureParameterBufferH264 pic_param;
VAEncSliceParameterBufferH264 slice_param;
VAPictureH264 current_curr_pic;
VAPictureH264 reference_frames[SURFACE_NUM];
VAPictureH264 ref_pic_list0_p[SURFACE_NUM * 2];
VAPictureH264 ref_pic_list0_b[SURFACE_NUM * 2];
VAPictureH264 ref_pic_list1_b[SURFACE_NUM * 2];
// Default entrypoint for Encode
int requested_entrypoint;
int selected_entrypoint;
uint32_t num_short_term;
int constraint_set_flag;
int h264_packedheader; /* support pack header? */
int h264_maxref;
int frame_width_mbaligned;
int frame_height_mbaligned;
uint32_t current_frame_num;
int current_frame_type;
uint64_t current_frame_encoding;
uint64_t current_frame_display;
uint64_t current_idr_display;
uint8_t* encoded_buffer;
VA264Config config;
} VA264Context;
namespace livekit_ffi {
class VaapiH264EncoderWrapper {
public:
VaapiH264EncoderWrapper();
~VaapiH264EncoderWrapper();
// Initialize the encoder with the given parameters.
bool Initialize(int width,
int height,
int bitrate,
int intra_period,
int idr_period,
int ip_period,
int frame_rate,
VAProfile profile,
int rc_mode);
// Encode a frame and return the encoded data.
bool Encode(int fourcc,
const uint8_t* y,
const uint8_t* u,
const uint8_t* v,
bool forceIDR,
std::vector<uint8_t>& output);
void UpdateRates(int frame_rate, int bitrate) {
if (context_) {
context_->config.frame_rate = frame_rate;
context_->config.bitrate = bitrate;
}
}
bool IsInitialized() const {
return initialized_;
}
// Release resources.
void Destroy();
private:
std::unique_ptr<VA264Context> context_;
std::unique_ptr<VaapiDisplay> va_display_;
bool initialized_ = false;
};
} // namespace livekit_ffi
#endif // VAAPI_H264_ENCODER_WRAPPER_H_