From d51847152c47cfbfbecec2b59c45efe5bdfab3a3 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sun, 14 May 2023 09:00:02 +0200 Subject: [PATCH] code, cmake: Remove legacy code --- CMakeLists.txt | 18 - source/encoders/encoder-aom-av1.cpp | 1699 --------------------------- source/encoders/encoder-aom-av1.hpp | 191 --- source/plugin.cpp | 36 - 4 files changed, 1944 deletions(-) delete mode 100644 source/encoders/encoder-aom-av1.cpp delete mode 100644 source/encoders/encoder-aom-av1.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bd6eaeec..ecf5a4f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,7 +293,6 @@ set(${PREFIX}ENABLE_ENCODER_FFMPEG_AMF ${FEATURE_DEPRECATED} CACHE BOOL "Enable set(${PREFIX}ENABLE_ENCODER_FFMPEG_NVENC ${FEATURE_UNSTABLE} CACHE BOOL "Enable NVENC Encoder in FFmpeg.") set(${PREFIX}ENABLE_ENCODER_FFMPEG_PRORES ${FEATURE_STABLE} CACHE BOOL "Enable ProRes Encoder in FFmpeg.") set(${PREFIX}ENABLE_ENCODER_FFMPEG_DNXHR ${FEATURE_STABLE} CACHE BOOL "Enable DNXHR Encoder in FFmpeg.") -set(${PREFIX}ENABLE_ENCODER_AOM_AV1 ${FEATURE_DEPRECATED} CACHE BOOL "Enable AOM AV1 Encoder.") ## Filters set(${PREFIX}ENABLE_FILTER_AUTOFRAMING ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable Auto-Framing Filter") @@ -1213,23 +1212,6 @@ if(T_CHECK) endif() endif() -# Encoder/AOM-AV1 -is_feature_enabled(ENCODER_AOM_AV1 T_CHECK) -if(T_CHECK) - list(APPEND PROJECT_PRIVATE_SOURCE - "source/encoders/codecs/av1.hpp" - "source/encoders/codecs/av1.cpp" - "source/encoders/encoder-aom-av1.hpp" - "source/encoders/encoder-aom-av1.cpp" - ) - list(APPEND PROJECT_INCLUDE_DIRS - ${AOM_INCLUDE_DIR} - ) - list(APPEND PROJECT_DEFINITIONS - ENABLE_ENCODER_AOM_AV1 - ) -endif() - # Filter/Auto-Framing is_feature_enabled(FILTER_AUTOFRAMING T_CHECK) if(T_CHECK) diff --git a/source/encoders/encoder-aom-av1.cpp b/source/encoders/encoder-aom-av1.cpp deleted file mode 100644 index 9728fe36..00000000 --- a/source/encoders/encoder-aom-av1.cpp +++ /dev/null @@ -1,1699 +0,0 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2021-2023 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END - -//--------------------------------------------------------------------------------// -// THIS FEATURE IS DEPRECATED. SUBMITTED PATCHES WILL BE REJECTED. -//--------------------------------------------------------------------------------// - -#include "encoder-aom-av1.hpp" -#include "util/util-logging.hpp" - -#include "warning-disable.hpp" -#include -#include -#include "warning-enable.hpp" - -#ifdef _DEBUG -#define ST_PREFIX "<%s> " -#define D_LOG_ERROR(x, ...) P_LOG_ERROR(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) -#define D_LOG_WARNING(x, ...) P_LOG_WARN(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) -#define D_LOG_INFO(x, ...) P_LOG_INFO(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) -#define D_LOG_DEBUG(x, ...) P_LOG_DEBUG(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) -#else -#define ST_PREFIX " " -#define D_LOG_ERROR(...) P_LOG_ERROR(ST_PREFIX __VA_ARGS__) -#define D_LOG_WARNING(...) P_LOG_WARN(ST_PREFIX __VA_ARGS__) -#define D_LOG_INFO(...) P_LOG_INFO(ST_PREFIX __VA_ARGS__) -#define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__) -#endif - -#define ST_I18N "Encoder.AOM.AV1" - -// Preset -#define ST_I18N_DEPRECATED ST_I18N ".Deprecated" -#define ST_I18N_ENCODER ST_I18N ".Encoder" -#define ST_I18N_ENCODER_USAGE ST_I18N_ENCODER ".Usage" -#define ST_I18N_ENCODER_USAGE_GOODQUALITY ST_I18N_ENCODER_USAGE ".GoodQuality" -#define ST_I18N_ENCODER_USAGE_REALTIME ST_I18N_ENCODER_USAGE ".RealTime" -#define ST_I18N_ENCODER_USAGE_ALLINTRA ST_I18N_ENCODER_USAGE ".AllIntra" -#define ST_KEY_ENCODER_USAGE "Encoder.Usage" -#define ST_I18N_ENCODER_CPUUSAGE ST_I18N_ENCODER ".CPUUsage" -#define ST_I18N_ENCODER_CPUUSAGE_0 ST_I18N_ENCODER ".CPUUsage.0" -#define ST_I18N_ENCODER_CPUUSAGE_1 ST_I18N_ENCODER ".CPUUsage.1" -#define ST_I18N_ENCODER_CPUUSAGE_2 ST_I18N_ENCODER ".CPUUsage.2" -#define ST_I18N_ENCODER_CPUUSAGE_3 ST_I18N_ENCODER ".CPUUsage.3" -#define ST_I18N_ENCODER_CPUUSAGE_4 ST_I18N_ENCODER ".CPUUsage.4" -#define ST_I18N_ENCODER_CPUUSAGE_5 ST_I18N_ENCODER ".CPUUsage.5" -#define ST_I18N_ENCODER_CPUUSAGE_6 ST_I18N_ENCODER ".CPUUsage.6" -#define ST_I18N_ENCODER_CPUUSAGE_7 ST_I18N_ENCODER ".CPUUsage.7" -#define ST_I18N_ENCODER_CPUUSAGE_8 ST_I18N_ENCODER ".CPUUsage.8" -#define ST_I18N_ENCODER_CPUUSAGE_9 ST_I18N_ENCODER ".CPUUsage.9" -#define ST_I18N_ENCODER_CPUUSAGE_10 ST_I18N_ENCODER ".CPUUsage.10" -#define ST_KEY_ENCODER_CPUUSAGE "Encoder.CPUUsage" -#define ST_KEY_ENCODER_PROFILE "Encoder.Profile" - -// Rate Control -#define ST_I18N_RATECONTROL ST_I18N ".RateControl" -#define ST_I18N_RATECONTROL_MODE ST_I18N_RATECONTROL ".Mode" -#define ST_I18N_RATECONTROL_MODE_CBR ST_I18N_RATECONTROL_MODE ".CBR" -#define ST_I18N_RATECONTROL_MODE_VBR ST_I18N_RATECONTROL_MODE ".VBR" -#define ST_I18N_RATECONTROL_MODE_CQ ST_I18N_RATECONTROL_MODE ".CQ" -#define ST_I18N_RATECONTROL_MODE_Q ST_I18N_RATECONTROL_MODE ".Q" -#define ST_KEY_RATECONTROL_MODE "RateControl.Mode" -#define ST_I18N_RATECONTROL_LOOKAHEAD ST_I18N_RATECONTROL ".LookAhead" -#define ST_KEY_RATECONTROL_LOOKAHEAD "RateControl.LookAhead" -#define ST_I18N_RATECONTROL_LIMITS ST_I18N_RATECONTROL ".Limits" -#define ST_I18N_RATECONTROL_LIMITS_BITRATE ST_I18N_RATECONTROL_LIMITS ".Bitrate" -#define ST_KEY_RATECONTROL_LIMITS_BITRATE "RateControl.Limits.Bitrate" -#define ST_I18N_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT ST_I18N_RATECONTROL_LIMITS_BITRATE ".Undershoot" -#define ST_KEY_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT "RateControl.Limits.Bitrate.Undershoot" -#define ST_I18N_RATECONTROL_LIMITS_BITRATE_OVERSHOOT ST_I18N_RATECONTROL_LIMITS_BITRATE ".Overshoot" -#define ST_KEY_RATECONTROL_LIMITS_BITRATE_OVERSHOOT "RateControl.Limits.Bitrate.Overshoot" -#define ST_I18N_RATECONTROL_LIMITS_QUALITY ST_I18N_RATECONTROL_LIMITS ".Quality" -#define ST_KEY_RATECONTROL_LIMITS_QUALITY "RateControl.Limits.Quality" -#define ST_I18N_RATECONTROL_LIMITS_QUANTIZER_MINIMUM ST_I18N_RATECONTROL_LIMITS ".Quantizer.Minimum" -#define ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MINIMUM "RateControl.Limits.Quantizer.Minimum" -#define ST_I18N_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM ST_I18N_RATECONTROL_LIMITS ".Quantizer.Maximum" -#define ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM "RateControl.Limits.Quantizer.Maximum" -#define ST_I18N_RATECONTROL_BUFFER ST_I18N_RATECONTROL ".Buffer" -#define ST_I18N_RATECONTROL_BUFFER_SIZE ST_I18N_RATECONTROL_BUFFER ".Size" -#define ST_KEY_RATECONTROL_BUFFER_SIZE "RateControl.Buffer.Size" -#define ST_I18N_RATECONTROL_BUFFER_SIZE_INITIAL ST_I18N_RATECONTROL_BUFFER_SIZE ".Initial" -#define ST_KEY_RATECONTROL_BUFFER_SIZE_INITIAL "RateControl.Buffer.Size.Initial" -#define ST_I18N_RATECONTROL_BUFFER_SIZE_OPTIMAL ST_I18N_RATECONTROL_BUFFER_SIZE ".Optimal" -#define ST_KEY_RATECONTROL_BUFFER_SIZE_OPTIMAL "RateControl.Buffer.Size.Optimal" - -// Key-Frames -#define ST_I18N_KEYFRAMES ST_I18N ".KeyFrames" -#define ST_I18N_KEYFRAMES_INTERVALTYPE ST_I18N_KEYFRAMES ".IntervalType" -#define ST_I18N_KEYFRAMES_INTERVALTYPE_SECONDS ST_I18N_KEYFRAMES_INTERVALTYPE ".Seconds" -#define ST_I18N_KEYFRAMES_INTERVALTYPE_FRAMES ST_I18N_KEYFRAMES_INTERVALTYPE ".Frames" -#define ST_KEY_KEYFRAMES_INTERVALTYPE "KeyFrames.IntervalType" -#define ST_I18N_KEYFRAMES_INTERVAL ST_I18N_KEYFRAMES ".Interval" -#define ST_KEY_KEYFRAMES_INTERVAL_SECONDS "KeyFrames.Interval.Seconds" -#define ST_KEY_KEYFRAMES_INTERVAL_FRAMES "KeyFrames.Interval.Frames" - -// Advanced -#define ST_I18N_ADVANCED ST_I18N ".Advanced" -#define ST_I18N_ADVANCED_THREADS ST_I18N_ADVANCED ".Threads" -#define ST_KEY_ADVANCED_THREADS "Advanced.Threads" -#define ST_I18N_ADVANCED_ROWMULTITHREADING ST_I18N_ADVANCED ".RowMultiThreading" -#define ST_KEY_ADVANCED_ROWMULTITHREADING "Advanced.RowMultiThreading" -#define ST_I18N_ADVANCED_TILE_COLUMNS ST_I18N_ADVANCED ".Tile.Columns" -#define ST_KEY_ADVANCED_TILE_COLUMNS "Advanced.Tile.Columns" -#define ST_I18N_ADVANCED_TILE_ROWS ST_I18N_ADVANCED ".Tile.Rows" -#define ST_KEY_ADVANCED_TILE_ROWS "Advanced.Tile.Rows" -#define ST_I18N_ADVANCED_TUNE ST_I18N_ADVANCED ".Tune" -#define ST_I18N_ADVANCED_TUNE_METRIC ST_I18N_ADVANCED_TUNE ".Metric" -#define ST_I18N_ADVANCED_TUNE_METRIC_PSNR ST_I18N_ADVANCED_TUNE_METRIC ".PSNR" -#define ST_I18N_ADVANCED_TUNE_METRIC_SSIM ST_I18N_ADVANCED_TUNE_METRIC ".SSIM" -#define ST_I18N_ADVANCED_TUNE_METRIC_VMAFWITHPREPROCESSING ST_I18N_ADVANCED_TUNE_METRIC ".VMAF.WithPreprocessing" -#define ST_I18N_ADVANCED_TUNE_METRIC_VMAFWITHOUTPREPROCESSING ST_I18N_ADVANCED_TUNE_METRIC ".VMAF.WithoutPreProcessing" -#define ST_I18N_ADVANCED_TUNE_METRIC_VMAFMAXGAIN ST_I18N_ADVANCED_TUNE_METRIC ".VMAF.MaxGain" -#define ST_I18N_ADVANCED_TUNE_METRIC_VMAFNEGMAXGAIN ST_I18N_ADVANCED_TUNE_METRIC ".VMAF.NegMaxGain" -#define ST_I18N_ADVANCED_TUNE_METRIC_BUTTERAUGLI ST_I18N_ADVANCED_TUNE_METRIC ".Butteraugli" -#define ST_KEY_ADVANCED_TUNE_METRIC "Advanced.Tune.Metric" -#define ST_I18N_ADVANCED_TUNE_CONTENT ST_I18N_ADVANCED_TUNE ".Content" -#define ST_I18N_ADVANCED_TUNE_CONTENT_SCREEN ST_I18N_ADVANCED_TUNE_CONTENT ".Screen" -#define ST_I18N_ADVANCED_TUNE_CONTENT_FILM ST_I18N_ADVANCED_TUNE_CONTENT ".Film" -#define ST_KEY_ADVANCED_TUNE_CONTENT "Advanced.Tune.Content" - -using namespace streamfx::encoder::aom::av1; - -static constexpr std::string_view HELP_URL = "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-AOM-AV1"; - -const char* obs_video_format_to_string(video_format format) -{ - switch (format) { - case VIDEO_FORMAT_I420: - return "I420"; - case VIDEO_FORMAT_NV12: - return "NV12"; - case VIDEO_FORMAT_YVYU: - return "YVYU"; - case VIDEO_FORMAT_YUY2: - return "YUY"; - case VIDEO_FORMAT_UYVY: - return "UYVY"; - case VIDEO_FORMAT_RGBA: - return "RGBA"; - case VIDEO_FORMAT_BGRA: - return "BGRA"; - case VIDEO_FORMAT_BGRX: - return "BGRX"; - case VIDEO_FORMAT_Y800: - return "Y800"; - case VIDEO_FORMAT_I444: - return "I444"; - case VIDEO_FORMAT_BGR3: - return "BGR3"; - case VIDEO_FORMAT_I422: - return "I422"; - case VIDEO_FORMAT_I40A: - return "I40A"; - case VIDEO_FORMAT_I42A: - return "I42A"; - case VIDEO_FORMAT_YUVA: - return "YUVA"; - case VIDEO_FORMAT_AYUV: - return "AYUV"; - default: - return "Unknown"; - } -} - -const char* aom_color_format_to_string(aom_img_fmt format) -{ - switch (format) { - case AOM_IMG_FMT_AOMYV12: - return "AOM-YV12"; - case AOM_IMG_FMT_AOMI420: - return "AOM-I420"; - case AOM_IMG_FMT_YV12: - return "YV12"; - case AOM_IMG_FMT_I420: - return "I420"; - case AOM_IMG_FMT_I422: - return "I422"; - case AOM_IMG_FMT_I444: - return "I444"; - case AOM_IMG_FMT_YV1216: - return "YV12-16"; - case AOM_IMG_FMT_I42016: - return "I420-16"; - case AOM_IMG_FMT_I42216: - return "I422-16"; - case AOM_IMG_FMT_I44416: - return "I444-16"; - default: - return "Unknown"; - } -} - -const char* aom_color_trc_to_string(aom_transfer_characteristics_t trc) -{ - switch (trc) { - case AOM_CICP_TC_BT_709: - return "Bt.709"; - case AOM_CICP_TC_BT_470_M: - return "Bt.407 M"; - case AOM_CICP_TC_BT_470_B_G: - return "Bt.407 B/G"; - case AOM_CICP_TC_BT_601: - return "Bt.601"; - case AOM_CICP_TC_SMPTE_240: - return "SMPTE 240 M"; - case AOM_CICP_TC_LINEAR: - return "Linear"; - case AOM_CICP_TC_LOG_100: - return "Logarithmic (100:1 range)"; - case AOM_CICP_TC_LOG_100_SQRT10: - return "Logarithmic (100*sqrt(10):1 range)"; - case AOM_CICP_TC_IEC_61966: - return "IEC 61966-2-4"; - case AOM_CICP_TC_BT_1361: - return "Bt.1361"; - case AOM_CICP_TC_SRGB: - return "sRGB"; - case AOM_CICP_TC_BT_2020_10_BIT: - return "Bt.2020 10b"; - case AOM_CICP_TC_BT_2020_12_BIT: - return "Bt.2020 12b"; - case AOM_CICP_TC_SMPTE_2084: - return "Bt.2100 PQ"; - case AOM_CICP_TC_SMPTE_428: - return "SMPTE ST 428"; - case AOM_CICP_TC_HLG: - return "Bt.2100 HLG"; - default: - return "Unknown"; - } -} - -const char* aom_rc_mode_to_string(aom_rc_mode mode) -{ - switch (mode) { - case AOM_VBR: - return "Variable Bitrate (VBR)"; - case AOM_CBR: - return "Constant Bitrate (CBR)"; - case AOM_CQ: - return "Constrained Quality (CQ)"; - case AOM_Q: - return "Constant Quality (Q)"; - default: - return "Unknown"; - } -} - -const char* aom_kf_mode_to_string(aom_kf_mode mode) -{ - switch (mode) { - case AOM_KF_AUTO: - return "Automatic"; - case AOM_KF_DISABLED: - return "Disabled"; - default: - return "Unknown"; - } -} - -const char* aom_tune_metric_to_string(aom_tune_metric tune) -{ - switch (tune) { - case AOM_TUNE_PSNR: - return "PSNR"; - case AOM_TUNE_SSIM: - return "SSIM"; - case AOM_TUNE_VMAF_WITH_PREPROCESSING: - return "VMAF w/ pre-processing"; - case AOM_TUNE_VMAF_WITHOUT_PREPROCESSING: - return "VMAF w/o pre-processing"; - case AOM_TUNE_VMAF_MAX_GAIN: - return "VMAF max. gain"; - case AOM_TUNE_VMAF_NEG_MAX_GAIN: - return "VMAF negative max. gain"; - case AOM_TUNE_BUTTERAUGLI: - return "Butteraugli"; - default: - return "Unknown"; - } -} - -const char* aom_tune_content_to_string(aom_tune_content tune) -{ - switch (tune) { - case AOM_CONTENT_DEFAULT: - return "Default"; - case AOM_CONTENT_FILM: - return "Film"; - case AOM_CONTENT_SCREEN: - return "Screen"; - default: - return "Unknown"; - } -} - -aom_av1_instance::aom_av1_instance(obs_data_t* settings, obs_encoder_t* self, bool is_hw) - : obs::encoder_instance(settings, self, is_hw), _factory(aom_av1_factory::get()), _iface(nullptr), _ctx(), _cfg(), - _image_index(0), _images(), _global_headers(nullptr), _initialized(false), _settings() -{ - if (is_hw) { - throw std::runtime_error("Hardware encoding isn't even registered, how did you get here?"); - } - - // Retrieve encoder interface. - _iface = _factory->libaom_codec_av1_cx(); - if (!_iface) { - throw std::runtime_error("AOM library does not provide AV1 encoder."); - } - -#ifdef ENABLE_PROFILING - // Profilers - _profiler_copy = streamfx::util::profiler::create(); - _profiler_encode = streamfx::util::profiler::create(); - _profiler_packet = streamfx::util::profiler::create(); -#endif - - { // Generate Static Configuration - { // OBS Information - video_scale_info ovsi; - video_t* video = obs_encoder_video(_self); - const struct video_output_info* video_info = video_output_get_info(video); - - ovsi.colorspace = video_info->colorspace; - ovsi.format = video_info->format; - ovsi.range = video_info->range; - get_video_info(&ovsi); - - // Video - _settings.width = static_cast(obs_encoder_get_width(_self)); - _settings.height = static_cast(obs_encoder_get_height(_self)); - _settings.fps.num = static_cast(video_info->fps_num); - _settings.fps.den = static_cast(video_info->fps_den); - - // Color Format - switch (ovsi.format) { - case VIDEO_FORMAT_I420: - _settings.color_format = AOM_IMG_FMT_I420; - break; - case VIDEO_FORMAT_I422: - _settings.color_format = AOM_IMG_FMT_I422; - break; - case VIDEO_FORMAT_I444: - _settings.color_format = AOM_IMG_FMT_I444; - break; - default: - throw std::runtime_error("Color Format is unknown."); - } - - // Color Space - switch (ovsi.colorspace) { - case VIDEO_CS_601: - _settings.color_primaries = AOM_CICP_CP_BT_601; - _settings.color_trc = AOM_CICP_TC_BT_601; - _settings.color_matrix = AOM_CICP_MC_BT_601; - break; - case VIDEO_CS_709: - _settings.color_primaries = AOM_CICP_CP_BT_709; - _settings.color_trc = AOM_CICP_TC_BT_709; - _settings.color_matrix = AOM_CICP_MC_BT_709; - break; - case VIDEO_CS_SRGB: - _settings.color_primaries = AOM_CICP_CP_BT_709; - _settings.color_trc = AOM_CICP_TC_SRGB; - _settings.color_matrix = AOM_CICP_MC_BT_709; - break; - default: - throw std::runtime_error("Color Space is unknown."); - } - - // Color Range - switch (ovsi.range) { - case VIDEO_RANGE_FULL: - _settings.color_range = AOM_CR_FULL_RANGE; - break; - case VIDEO_RANGE_PARTIAL: - _settings.color_range = AOM_CR_STUDIO_RANGE; - break; - default: - throw std::runtime_error("Color Range is unknown."); - } - - // Monochrome - _settings.monochrome = (video_info->format == VIDEO_FORMAT_Y800); - } - - { // Encoder - _settings.profile = static_cast(obs_data_get_int(settings, ST_KEY_ENCODER_PROFILE)); - if (_settings.profile == codec::av1::profile::UNKNOWN) { - // Resolve the automatic profile to a proper value. - bool need_professional = (_settings.color_format == AOM_IMG_FMT_I422); - bool need_high = (_settings.color_format == AOM_IMG_FMT_I444) || _settings.monochrome; - - if (need_professional) { - _settings.profile = codec::av1::profile::PROFESSIONAL; - } else if (need_high) { - _settings.profile = codec::av1::profile::HIGH; - } else { - _settings.profile = codec::av1::profile::MAIN; - } - } - } - - { // Rate Control - _settings.rc_mode = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE)); - _settings.rc_lookahead = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LOOKAHEAD)); - } - - { // Threading - if (auto threads = obs_data_get_int(settings, ST_KEY_ADVANCED_THREADS); threads > 0) { - _settings.threads = static_cast(threads); - } else { - _settings.threads = static_cast(std::thread::hardware_concurrency()); - } - _settings.rowmultithreading = - static_cast(obs_data_get_int(settings, ST_KEY_ADVANCED_ROWMULTITHREADING)); - } - - { // Tiling - _settings.tile_columns = static_cast(obs_data_get_int(settings, ST_KEY_ADVANCED_TILE_COLUMNS)); - _settings.tile_rows = static_cast(obs_data_get_int(settings, ST_KEY_ADVANCED_TILE_ROWS)); - } - - { // Tuning - if (auto v = obs_data_get_int(settings, ST_KEY_ADVANCED_TUNE_METRIC); v != -1) { - _settings.tune_metric = static_cast(v); - } - _settings.tune_content = - static_cast(obs_data_get_int(settings, ST_KEY_ADVANCED_TUNE_CONTENT)); - } - } - - // Apply Settings - update(settings); - - // Initialize Encoder - if (auto error = _factory->libaom_codec_enc_init_ver(&_ctx, _iface, &_cfg, 0, AOM_ENCODER_ABI_VERSION); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - D_LOG_ERROR("Failed to initialize codec, unexpected error: %s (code %" PRIu32 ")", errstr, error); - throw std::runtime_error(errstr); - } - - { // Apply Static Control Settings - - { // Color Information -#ifdef AOM_CTRL_AV1E_SET_COLOR_PRIMARIES - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_COLOR_PRIMARIES, _settings.color_primaries); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_COLOR_PRIMARIES", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#else - D_LOG_ERROR("AOM library was built without AV1E_SET_COLOR_PRIMARIES, behavior is unknown."); -#endif - -#ifdef AOM_CTRL_AV1E_SET_TRANSFER_CHARACTERISTICS - if (auto error = - _factory->libaom_codec_control(&_ctx, AV1E_SET_TRANSFER_CHARACTERISTICS, _settings.color_trc); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_TRANSFER_CHARACTERISTICS", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#else - D_LOG_ERROR("AOM library was built without AV1E_SET_TRANSFER_CHARACTERISTICS, behavior is unknown."); -#endif - -#ifdef AOM_CTRL_AV1E_SET_MATRIX_COEFFICIENTS - if (auto error = - _factory->libaom_codec_control(&_ctx, AV1E_SET_MATRIX_COEFFICIENTS, _settings.color_matrix); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_MATRIX_COEFFICIENTS", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#else - D_LOG_ERROR("AOM library was built without AV1E_SET_MATRIX_COEFFICIENTS, behavior is unknown."); -#endif - -#ifdef AOM_CTRL_AV1E_SET_COLOR_RANGE - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_COLOR_RANGE, _settings.color_range); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_COLOR_RANGE", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#else - D_LOG_ERROR("AOM library was built without AV1_SET_COLOR_RANGE, behavior is unknown."); -#endif - -#ifdef AOM_CTRL_AV1E_SET_CHROMA_SAMPLE_POSITION - // !TODO: Consider making this user-controlled. At the moment, this follows the H.264 chroma standard. - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_CHROMA_SAMPLE_POSITION, AOM_CSP_VERTICAL); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_CHROMA_SAMPLE_POSITION", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_RENDER_SIZE - int32_t size[2] = {_settings.width, _settings.height}; - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_RENDER_SIZE, &size); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_RENDER_SIZE", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } -#endif - } - - // Apply Dynamic Control Settings - if (!update(settings)) { - throw std::runtime_error("Unexpected error during configuration."); - } - } - - // Preallocate global headers. - _global_headers = _factory->libaom_codec_get_global_headers(&_ctx); - - // Allocate frames. - _images.resize(_cfg.g_threads); - for (auto& image : _images) { - _factory->libaom_img_alloc(&image, _settings.color_format, _settings.width, _settings.height, 8); - - // Color Information. - image.fmt = _settings.color_format; - image.cp = _settings.color_primaries; - image.tc = _settings.color_trc; - image.mc = _settings.color_matrix; - image.range = _settings.color_range; - image.monochrome = _settings.monochrome ? 1 : 0; - image.csp = AOM_CSP_VERTICAL; // !TODO: Consider making this user-controlled. - - // Size - image.r_w = image.d_w; - image.r_h = image.d_h; - image.r_w = image.w; - image.r_h = image.h; - } - - // Log Settings - log(); - - // Signal to future update() calls that we are fully initialized. - _initialized = true; -} - -aom_av1_instance::~aom_av1_instance() -{ -#ifdef ENABLE_PROFILING - // Profiling - D_LOG_INFO("Timings | Avg. µs | 99.9ile µs | 99.0ile µs | 95.0ile µs | Samples ", ""); - D_LOG_INFO("--------+---------------+---------------+---------------+---------------+----------", ""); - D_LOG_INFO("Copy | %13.1f | %13" PRId64 " | %13" PRId64 " | %13" PRId64 " | %9" PRIu64, - _profiler_copy->average_duration() / 1000., - std::chrono::duration_cast(_profiler_copy->percentile(0.999)).count(), - std::chrono::duration_cast(_profiler_copy->percentile(0.990)).count(), - std::chrono::duration_cast(_profiler_copy->percentile(0.950)).count(), - _profiler_copy->count()); - D_LOG_INFO("Encode | %13.1f | %13" PRId64 " | %13" PRId64 " | %13" PRId64 " | %9" PRIu64, - _profiler_encode->average_duration() / 1000., - std::chrono::duration_cast(_profiler_encode->percentile(0.999)).count(), - std::chrono::duration_cast(_profiler_encode->percentile(0.990)).count(), - std::chrono::duration_cast(_profiler_encode->percentile(0.950)).count(), - _profiler_encode->count()); - D_LOG_INFO("Packet | %13.1f | %13" PRId64 " | %13" PRId64 " | %13" PRId64 " | %9" PRIu64, - _profiler_packet->average_duration() / 1000., - std::chrono::duration_cast(_profiler_packet->percentile(0.999)).count(), - std::chrono::duration_cast(_profiler_packet->percentile(0.990)).count(), - std::chrono::duration_cast(_profiler_packet->percentile(0.950)).count(), - _profiler_packet->count()); -#endif - - // Deallocate global buffer. - if (_global_headers) { - /* Breaks heap - if (_global_headers->buf) { - free(_global_headers->buf); - _global_headers->buf = nullptr; - } - free(_global_headers); - _global_headers = nullptr; - */ - } - - // Deallocate frames. - for (auto& image : _images) { - _factory->libaom_img_free(&image); - } - _images.clear(); - - // Destroy encoder. - _factory->libaom_codec_destroy(&_ctx); -} - -void aom_av1_instance::migrate(obs_data_t* settings, uint64_t version) {} - -bool aom_av1_instance::update(obs_data_t* settings) -{ - video_t* obsVideo = obs_encoder_video(_self); - const struct video_output_info* obsVideoInfo = video_output_get_info(obsVideo); - uint32_t obsFPSnum = obsVideoInfo->fps_num; - uint32_t obsFPSden = obsVideoInfo->fps_den; - bool obsMonochrome = (obsVideoInfo->format == VIDEO_FORMAT_Y800); - -#define SET_IF_NOT_DEFAULT(X, Y) \ - if (X != -1) { \ - Y = static_cast(X); \ - } - - { // Generate Dynamic Settings - - { // Encoder - _settings.preset = static_cast(obs_data_get_int(settings, ST_KEY_ENCODER_CPUUSAGE)); - } - - { // Rate Control - _settings.rc_bitrate = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE)); - _settings.rc_bitrate_overshoot = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT)); - _settings.rc_bitrate_undershoot = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_OVERSHOOT)); - _settings.rc_quality = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY)); - _settings.rc_quantizer_min = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MINIMUM)); - _settings.rc_quantizer_max = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM)); - _settings.rc_buffer_ms = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE)); - _settings.rc_buffer_initial_ms = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE_INITIAL)); - _settings.rc_buffer_optimal_ms = - static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE_OPTIMAL)); - } - - { // Key-Frames - int64_t kf_type = obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVALTYPE); - bool is_seconds = (kf_type == 0); - - _settings.kf_mode = AOM_KF_AUTO; - if (is_seconds) { - _settings.kf_distance_max = static_cast( - std::lround(obs_data_get_double(settings, ST_KEY_KEYFRAMES_INTERVAL_SECONDS) - * static_cast(obsFPSnum) / static_cast(obsFPSden))); - } else { - _settings.kf_distance_max = - static_cast(obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVAL_FRAMES)); - } - _settings.kf_distance_min = _settings.kf_distance_max; - } - - // All-Intra requires us to never set Key-Frames. - if (_cfg.g_usage == AOM_USAGE_ALL_INTRA) { - _settings.rc_lookahead = 0; - _settings.kf_mode = AOM_KF_DISABLED; - _settings.kf_distance_min = 0; - _settings.kf_distance_max = 0; - } - } - - { // Configuration. - - { // Usage and Defaults - _cfg.g_usage = static_cast(obs_data_get_int(settings, ST_KEY_ENCODER_USAGE)); - _factory->libaom_codec_enc_config_default(_iface, &_cfg, _cfg.g_usage); - } - - { // Frame Information - // Size - _cfg.g_w = _settings.width; - _cfg.g_h = _settings.height; - - // Time Base (Rate is inverted Time Base) - _cfg.g_timebase.num = static_cast(_settings.fps.den); - _cfg.g_timebase.den = static_cast(_settings.fps.num); - - // !INFO: Whenever OBS decides to support anything but 8-bits, let me know. - _cfg.g_bit_depth = AOM_BITS_8; - _cfg.g_input_bit_depth = AOM_BITS_8; - - // Monochrome color - _cfg.monochrome = _settings.monochrome ? 1u : 0u; - } - - { // Encoder - - // AV1 Profile - _cfg.g_profile = static_cast(_settings.profile); - } - - { // Rate Control - // Mode - _cfg.rc_end_usage = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE)); - - // Look-Ahead - SET_IF_NOT_DEFAULT(_settings.rc_lookahead, _cfg.g_lag_in_frames); - - // Limits - SET_IF_NOT_DEFAULT(_settings.rc_bitrate, _cfg.rc_target_bitrate); - SET_IF_NOT_DEFAULT(_settings.rc_bitrate_overshoot, _cfg.rc_overshoot_pct); - SET_IF_NOT_DEFAULT(_settings.rc_bitrate_undershoot, _cfg.rc_undershoot_pct); - SET_IF_NOT_DEFAULT(_settings.rc_quantizer_min, _cfg.rc_min_quantizer); - SET_IF_NOT_DEFAULT(_settings.rc_quantizer_max, _cfg.rc_max_quantizer); - - // Buffer - SET_IF_NOT_DEFAULT(_settings.rc_buffer_ms, _cfg.rc_buf_sz); - SET_IF_NOT_DEFAULT(_settings.rc_buffer_initial_ms, _cfg.rc_buf_initial_sz); - SET_IF_NOT_DEFAULT(_settings.rc_buffer_optimal_ms, _cfg.rc_buf_optimal_sz); - } - - { // Key-Frames - SET_IF_NOT_DEFAULT(_settings.kf_mode, _cfg.kf_mode); - SET_IF_NOT_DEFAULT(_settings.kf_distance_min, _cfg.kf_min_dist); - SET_IF_NOT_DEFAULT(_settings.kf_distance_max, _cfg.kf_max_dist); - } - - { // Advanced - - // Single-Pass - _cfg.g_pass = AOM_RC_ONE_PASS; - - // Threading - SET_IF_NOT_DEFAULT(_settings.threads, _cfg.g_threads); - } - - // TODO: Future - //_cfg.rc_resize_mode = 0; // "RESIZE_NONE - //_cfg.rc_resize_denominator = ?; - //_cfg.rc_resize_kf_denominator = ?; - //_cfg.rc_superres_mode = AOM_SUPERRES_NONE; - //_cfg.rc_superres_denominator = ?; - //_cfg.rc_superres_kf_denominator = ?; - //_cfg.rc_superres_qthresh = ?; - //_cfg.rc_superres_kf_qtresh = ?; - //_cfg.rc_dropframe_thresh = ?; - //_cfg.fwd_kf_enabled = ?; - //_cfg.g_forced_max_frame_width = ?; - //_cfg.g_forced_max_frame_height = ?; - //_cfg.g_error_resilient = ?; - //_cfg.g_lag_in_frames = ?; - //_cfg.sframe_dist = ?; - //_cfg.sframe_mode = 0; - //_cfg.large_scale_tile = 0; - //_cfg.full_still_picture_hdr = ?; - //_cfg.save_as_annexb = ?; - //_cfg.encoder_cfg = ?; - - // Apply configuration - if (_initialized) { - if (auto error = _factory->libaom_codec_enc_config_set(&_ctx, &_cfg); error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing configuration: %s (code %" PRIu32 ")%s%s%s%s", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - return false; - } - } - } - - if (_ctx.iface) { // Control - - { // Encoder -#ifdef AOM_CTRL_AOME_SET_CPUUSED - if (_settings.preset != -1) { - if (auto error = _factory->libaom_codec_control(&_ctx, AOME_SET_CPUUSED, _settings.preset); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AOME_SET_CPUUSED", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif - } - - { // Rate Control -#ifdef AOM_CTRL_AOME_SET_CQ_LEVEL - if ((_settings.rc_quality != -1) && ((_settings.rc_mode == AOM_CQ) || (_settings.rc_mode == AOM_Q))) { - if (auto error = _factory->libaom_codec_control(&_ctx, AOME_SET_CQ_LEVEL, _settings.rc_quality); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AOME_SET_CQ_LEVEL", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif - } - - { // Advanced -#ifdef AOM_CTRL_AV1E_SET_ROW_MT - if (_settings.rowmultithreading != -1) { - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_ROW_MT, _settings.rowmultithreading); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_ROW_MT", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_TILE_COLUMNS - if (_settings.tile_columns != -1) { - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_TILE_COLUMNS, _settings.tile_columns); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_TILE_COLUMNS", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_TILE_ROWS - if (_settings.tile_rows != -1) { - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_TILE_ROWS, _settings.tile_rows); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_TILE_ROWS", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif -#ifdef AOM_CTRL_AOME_SET_TUNING - if (_settings.tune_metric != -1) { - if (auto error = _factory->libaom_codec_control(&_ctx, AOME_SET_TUNING, _settings.tune_metric); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AOME_SET_TUNING", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif -#ifdef AOM_CTRL_AV1E_SET_TUNE_CONTENT - if (_settings.tune_content != AOM_CONTENT_DEFAULT) { - if (auto error = _factory->libaom_codec_control(&_ctx, AV1E_SET_TUNE_CONTENT, _settings.tune_content); - error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - const char* err = _factory->libaom_codec_error(&_ctx); - const char* errdtl = _factory->libaom_codec_error_detail(&_ctx); - D_LOG_WARNING("Error changing '%s': %s (code %" PRIu32 ")%s%s%s%s", // - "AV1E_SET_TUNE_CONTENT", // - (errstr ? errstr : ""), error, // - (err ? "\n\tMessage: " : ""), (err ? err : ""), // - (errdtl ? "\n\tDetails: " : ""), (errdtl ? errdtl : "") // - ); - } - } -#endif - } - } - -#undef SET_IF_NOT_DEFAULT - - // Log the changed settings. - if (_initialized) { - log(); - } - - return true; -} - -void aom_av1_instance::log() -{ - D_LOG_INFO("AOM AV1:", ""); - D_LOG_INFO(" Video: %" PRIu16 "x%" PRIu16 "@%1.2ffps (%" PRIu32 "/%" PRIu32 ")", _settings.width, _settings.height, - static_cast(_settings.fps.num) / static_cast(_settings.fps.den), _settings.fps.num, - _settings.fps.den); - D_LOG_INFO(" Color: %s/%s/%s%s", aom_color_format_to_string(_settings.color_format), - aom_color_trc_to_string(_settings.color_trc), - _settings.color_range == AOM_CR_FULL_RANGE ? "Full" : "Partial", - _settings.monochrome ? "/Monochrome" : ""); - - // Rate Control - D_LOG_INFO(" Rate Control: %s", aom_rc_mode_to_string(_settings.rc_mode)); - D_LOG_INFO(" Look-Ahead: %" PRId8, _settings.rc_lookahead); - D_LOG_INFO(" Buffers: %" PRId32 " ms / %" PRId32 " ms / %" PRId32 " ms", _settings.rc_buffer_ms, - _settings.rc_buffer_initial_ms, _settings.rc_buffer_optimal_ms); - D_LOG_INFO(" Bitrate: %" PRId32 " kbit/s (-%" PRId32 "%% - +%" PRId32 "%%)", _settings.rc_bitrate, - _settings.rc_bitrate_undershoot, _settings.rc_bitrate_overshoot); - D_LOG_INFO(" Quality: %" PRId8, _settings.rc_quality); - D_LOG_INFO(" Quantizer: %" PRId8 " - %" PRId8, _settings.rc_quantizer_min, _settings.rc_quantizer_max); - - // Key-Frames - D_LOG_INFO(" Key-Frames: %s", aom_kf_mode_to_string(_settings.kf_mode)); - D_LOG_INFO(" Distance: %" PRId32 " - %" PRId32 " frames", _settings.kf_distance_min, _settings.kf_distance_max); - - // Advanced - D_LOG_INFO(" Advanced: ", ""); - D_LOG_INFO(" Threads: %" PRId8, _settings.threads); - D_LOG_INFO(" Row-Multi-Threading: %s", _settings.rowmultithreading == -1 ? "Default" - : _settings.rowmultithreading == 1 ? "Enabled" - : "Disabled"); - D_LOG_INFO(" Tiling: %" PRId8 "x%" PRId8, _settings.tile_columns, _settings.tile_rows); - D_LOG_INFO(" Tune: %s (Metric), %s (Content)", aom_tune_metric_to_string(_settings.tune_metric), - aom_tune_content_to_string(_settings.tune_content)); -} - -bool aom_av1_instance::get_extra_data(uint8_t** extra_data, size_t* size) -{ - if (!_global_headers) { - return false; - } - - *extra_data = static_cast(_global_headers->buf); - *size = _global_headers->sz; - - return true; -} - -bool aom_av1_instance::get_sei_data(uint8_t** sei_data, size_t* size) -{ - return get_extra_data(sei_data, size); -} - -void aom_av1_instance::get_video_info(struct video_scale_info* info) -{ - // Fix up color format. - auto format = obs_encoder_get_preferred_video_format(_self); - if (format == VIDEO_FORMAT_NONE) { - format = info->format; - } - - switch (format) { - // Perfect matches. - case VIDEO_FORMAT_I444: // AOM_IMG_I444. - case VIDEO_FORMAT_I422: // AOM_IMG_I422. - case VIDEO_FORMAT_I420: // AOM_IMG_I420. - break; - - // 4:2:0 formats - case VIDEO_FORMAT_NV12: // Y, UV Interleaved. - case VIDEO_FORMAT_I40A: - D_LOG_WARNING("Color-format '%s' is not supported, forcing 'I420'...", obs_video_format_to_string(format)); - info->format = VIDEO_FORMAT_I420; - break; - - // 4:2:2-like formats - case VIDEO_FORMAT_UYVY: - case VIDEO_FORMAT_YUY2: - case VIDEO_FORMAT_YVYU: - case VIDEO_FORMAT_I42A: - D_LOG_WARNING("Color-format '%s' is not supported, forcing 'I422'...", obs_video_format_to_string(format)); - info->format = VIDEO_FORMAT_I422; - break; - - // 4:4:4 - case VIDEO_FORMAT_BGR3: - case VIDEO_FORMAT_BGRA: - case VIDEO_FORMAT_BGRX: - case VIDEO_FORMAT_RGBA: - case VIDEO_FORMAT_YUVA: - case VIDEO_FORMAT_AYUV: - case VIDEO_FORMAT_Y800: // Grayscale, no exact match. - D_LOG_WARNING("Color-format '%s' is not supported, forcing 'I444'...", obs_video_format_to_string(format)); - info->format = VIDEO_FORMAT_I444; - break; - default: - throw std::runtime_error("Color Format is unknown."); - } - - // Fix up color space. - if (info->colorspace == VIDEO_CS_DEFAULT) { - info->colorspace = VIDEO_CS_SRGB; - } - - // Fix up color range. - if (info->range == VIDEO_RANGE_DEFAULT) { - info->range = VIDEO_RANGE_PARTIAL; - } -} - -bool streamfx::encoder::aom::av1::aom_av1_instance::encode_video(encoder_frame* frame, encoder_packet* packet, - bool* received_packet) -{ - // Retrieve current indexed image. - auto& image = _images.at(_image_index); - - { // Copy Image data. -#ifdef ENABLE_PROFILING - auto profile = _profiler_copy->track(); -#endif - std::memcpy(image.planes[AOM_PLANE_Y], frame->data[0], frame->linesize[0] * image.h); - if (image.fmt == AOM_IMG_FMT_I420) { - std::memcpy(image.planes[AOM_PLANE_U], frame->data[1], frame->linesize[1] * image.h / 2); - std::memcpy(image.planes[AOM_PLANE_V], frame->data[2], frame->linesize[2] * image.h / 2); - } else { - std::memcpy(image.planes[AOM_PLANE_U], frame->data[1], frame->linesize[1] * image.h); - std::memcpy(image.planes[AOM_PLANE_V], frame->data[2], frame->linesize[2] * image.h); - } - } - - { // Try to encode the new image. -#ifdef ENABLE_PROFILING - auto profile = _profiler_encode->track(); -#endif - aom_enc_frame_flags_t flags = 0; - if (_cfg.g_usage == AOM_USAGE_ALL_INTRA) { - flags = AOM_EFLAG_FORCE_KF; - } - if (auto error = _factory->libaom_codec_encode(&_ctx, &image, frame->pts, 1, flags); error != AOM_CODEC_OK) { - const char* errstr = _factory->libaom_codec_err_to_string(error); - D_LOG_ERROR("Encoding frame failed with error: %s (code %" PRIu32 ")\n%s\n%s", errstr, error, - _factory->libaom_codec_error(&_ctx), _factory->libaom_codec_error_detail(&_ctx)); - return false; - } else { - // Increment the image index. - _image_index = (_image_index++) % _images.size(); - } - } - - { // Get Packet -#ifdef ENABLE_PROFILING - auto profile = _profiler_packet->track(); -#endif - aom_codec_iter_t iter = NULL; - for (auto* pkt = _factory->libaom_codec_get_cx_data(&_ctx, &iter); pkt != nullptr; - pkt = _factory->libaom_codec_get_cx_data(&_ctx, &iter)) { -#ifdef _DEBUG - { - const char* kind = ""; - switch (pkt->kind) { - case AOM_CODEC_CX_FRAME_PKT: - kind = "Frame"; - break; - case AOM_CODEC_STATS_PKT: - kind = "Stats"; - break; - case AOM_CODEC_FPMB_STATS_PKT: - kind = "FPMB Stats"; - break; - case AOM_CODEC_PSNR_PKT: - kind = "PSNR"; - break; - case AOM_CODEC_CUSTOM_PKT: - kind = "Custom"; - break; - } - D_LOG_DEBUG("\tPacket: Kind=%s", kind) - } -#endif - - if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { - // Status - packet->type = OBS_ENCODER_VIDEO; - packet->keyframe = ((pkt->data.frame.flags & AOM_FRAME_IS_KEY) == AOM_FRAME_IS_KEY) - || (_cfg.g_usage == AOM_USAGE_ALL_INTRA); - if (packet->keyframe) { - // - packet->priority = 3; // OBS_NAL_PRIORITY_HIGHEST - packet->drop_priority = 3; // OBS_NAL_PRIORITY_HIGHEST - } else if ((pkt->data.frame.flags & AOM_FRAME_IS_DROPPABLE) != AOM_FRAME_IS_DROPPABLE) { - // Dropping this frame breaks the bitstream. - packet->priority = 2; // OBS_NAL_PRIORITY_HIGH - packet->drop_priority = 3; // OBS_NAL_PRIORITY_HIGHEST - } else { - // This frame can be dropped at will. - packet->priority = 0; // OBS_NAL_PRIORITY_DISPOSABLE - packet->drop_priority = 0; // OBS_NAL_PRIORITY_DISPOSABLE - } - - // Data - packet->data = static_cast(pkt->data.frame.buf); - packet->size = pkt->data.frame.sz; - - // Timestamps - //TODO: Temporarily set both to the same until there is a way to figure out actual order. - packet->pts = pkt->data.frame.pts; - packet->dts = pkt->data.frame.pts; - - *received_packet = true; - } - - if (*received_packet == true) - break; - } - - if (!*received_packet) { - packet->type = OBS_ENCODER_VIDEO; - packet->data = nullptr; - packet->size = 0; - packet->pts = -1; - packet->dts = -1; -#ifdef _DEBUG - D_LOG_DEBUG("No Packet", ""); -#endif - // Not necessarily an error. - //return false; - } else { -#ifdef _DEBUG - D_LOG_DEBUG("Packet: Type=%s PTS=%06" PRId64 " DTS=%06" PRId64 " Size=%016" PRIuPTR "", - packet->keyframe ? "I" : "P", packet->pts, packet->dts, packet->size); -#endif - } - } - - return true; -} - -aom_av1_factory::aom_av1_factory() -{ - // Try and load the AOM library. - std::vector libs; - -#ifdef D_PLATFORM_WINDOWS - // Try loading from the data directory first. - libs.push_back(streamfx::data_file_path("aom.dll")); // MSVC (preferred) - libs.push_back(streamfx::data_file_path("libaom.dll")); // Cross-Compile - // In any other case, load the system-wide binary. - libs.push_back("aom.dll"); - libs.push_back("libaom.dll"); -#else - // Try loading from the data directory first. - libs.push_back(streamfx::data_file_path("libaom.so")); - // In any other case, load the system-wide binary. - libs.push_back("libaom"); -#endif - - for (auto lib : libs) { - try { - _library = streamfx::util::library::load(lib); - if (_library) - break; - } catch (...) { - D_LOG_WARNING("Loading of '%s' failed.", lib.generic_string().c_str()); - } - } - if (!_library) { - throw std::runtime_error("Unable to load AOM library."); - } - - // Load all necessary functions. -#define _LOAD_SYMBOL(X) \ - { \ - lib##X = reinterpret_cast(_library->load_symbol(std::string(#X))); \ - } -#define _LOAD_SYMBOL_(X, Y) \ - { \ - lib##X = reinterpret_cast(_library->load_symbol(std::string(Y))); \ - } - _LOAD_SYMBOL(aom_codec_version); - _LOAD_SYMBOL(aom_codec_version_str); - _LOAD_SYMBOL(aom_codec_version_extra_str); - _LOAD_SYMBOL(aom_codec_build_config); - _LOAD_SYMBOL(aom_codec_iface_name); - _LOAD_SYMBOL(aom_codec_err_to_string); - _LOAD_SYMBOL(aom_codec_error); - _LOAD_SYMBOL(aom_codec_error_detail); - _LOAD_SYMBOL(aom_codec_destroy); - _LOAD_SYMBOL(aom_codec_get_caps); - _LOAD_SYMBOL(aom_codec_control); - _LOAD_SYMBOL(aom_codec_set_option); - _LOAD_SYMBOL(aom_obu_type_to_string); - _LOAD_SYMBOL(aom_uleb_size_in_bytes); - _LOAD_SYMBOL(aom_uleb_decode); - _LOAD_SYMBOL(aom_uleb_encode); - _LOAD_SYMBOL(aom_uleb_encode_fixed_size); - _LOAD_SYMBOL(aom_img_alloc); - _LOAD_SYMBOL(aom_img_wrap); - _LOAD_SYMBOL(aom_img_alloc_with_border); - _LOAD_SYMBOL(aom_img_set_rect); - _LOAD_SYMBOL(aom_img_flip); - _LOAD_SYMBOL(aom_img_free); - _LOAD_SYMBOL(aom_img_plane_width); - _LOAD_SYMBOL(aom_img_plane_height); - _LOAD_SYMBOL(aom_img_add_metadata); - _LOAD_SYMBOL(aom_img_get_metadata); - _LOAD_SYMBOL(aom_img_num_metadata); - _LOAD_SYMBOL(aom_img_remove_metadata); - _LOAD_SYMBOL(aom_img_metadata_alloc); - _LOAD_SYMBOL(aom_img_metadata_free); - _LOAD_SYMBOL(aom_codec_enc_init_ver); - _LOAD_SYMBOL(aom_codec_enc_config_default); - _LOAD_SYMBOL(aom_codec_enc_config_set); - _LOAD_SYMBOL(aom_codec_get_global_headers); - _LOAD_SYMBOL(aom_codec_encode); - _LOAD_SYMBOL(aom_codec_set_cx_data_buf); - _LOAD_SYMBOL(aom_codec_get_cx_data); - _LOAD_SYMBOL(aom_codec_get_preview_frame); - _LOAD_SYMBOL(aom_codec_av1_cx); -#undef _LOAD_SYMBOL - - // Register encoder. - _info.id = S_PREFIX "aom-av1"; - _info.type = obs_encoder_type::OBS_ENCODER_VIDEO; - _info.codec = "av1"; - _info.caps = OBS_ENCODER_CAP_DYN_BITRATE; - _info.caps |= OBS_ENCODER_CAP_DEPRECATED; - - finish_setup(); -} - -aom_av1_factory::~aom_av1_factory() {} - -std::shared_ptr _aom_av1_factory_instance = nullptr; - -void aom_av1_factory::initialize() -{ - try { - if (!_aom_av1_factory_instance) { - _aom_av1_factory_instance = std::make_shared(); - } - } catch (std::exception const& ex) { - D_LOG_ERROR("Failed to initialize AOM AV1 encoder: %s", ex.what()); - } -} - -void aom_av1_factory::finalize() -{ - _aom_av1_factory_instance.reset(); -} - -std::shared_ptr aom_av1_factory::get() -{ - return _aom_av1_factory_instance; -} - -const char* aom_av1_factory::get_name() -{ - return "AV1 (via AOM)"; -} - -void* aom_av1_factory::create(obs_data_t* settings, obs_encoder_t* encoder, bool is_hw) -{ - return new aom_av1_instance(settings, encoder, is_hw); -} - -void aom_av1_factory::get_defaults2(obs_data_t* settings) -{ - { // Presets - obs_data_set_default_int(settings, ST_KEY_ENCODER_USAGE, static_cast(AOM_USAGE_REALTIME)); - obs_data_set_default_int(settings, ST_KEY_ENCODER_CPUUSAGE, -1); - obs_data_set_default_int(settings, ST_KEY_ENCODER_PROFILE, - static_cast(codec::av1::profile::UNKNOWN)); - } - - { // Rate-Control - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_MODE, static_cast(AOM_CBR)); - - // Limits - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE, 6000); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_OVERSHOOT, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MINIMUM, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM, -1); - - // Buffer - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE_INITIAL, -1); - obs_data_set_default_int(settings, ST_KEY_RATECONTROL_BUFFER_SIZE_OPTIMAL, -1); - } - - { // Key-Frame Options - obs_data_set_default_int(settings, ST_KEY_KEYFRAMES_INTERVALTYPE, 0); - obs_data_set_default_double(settings, ST_KEY_KEYFRAMES_INTERVAL_SECONDS, 2.0); - obs_data_set_default_int(settings, ST_KEY_KEYFRAMES_INTERVAL_FRAMES, 300); - } - - { // Advanced Options - obs_data_set_default_int(settings, ST_KEY_ADVANCED_THREADS, 0); - obs_data_set_default_int(settings, ST_KEY_ADVANCED_ROWMULTITHREADING, -1); - obs_data_set_default_int(settings, ST_KEY_ADVANCED_TILE_COLUMNS, -1); - obs_data_set_default_int(settings, ST_KEY_ADVANCED_TILE_ROWS, -1); - obs_data_set_default_int(settings, ST_KEY_ADVANCED_TUNE_METRIC, -1); - obs_data_set_default_int(settings, ST_KEY_ADVANCED_TUNE_CONTENT, static_cast(AOM_CONTENT_DEFAULT)); - } -} - -static bool modified_usage(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept -{ - try { - bool is_all_intra = false; - if (obs_data_get_int(settings, ST_KEY_ENCODER_USAGE) == AOM_USAGE_ALL_INTRA) { - is_all_intra = true; - } - - // All-Intra does not support these. - obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LOOKAHEAD), !is_all_intra); - obs_property_set_visible(obs_properties_get(props, ST_I18N_KEYFRAMES), !is_all_intra); - - return true; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return false; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return false; - } -} - -static bool modified_ratecontrol_mode(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept -{ - try { - bool is_bitrate_visible = false; - bool is_overundershoot_visible = false; - bool is_quality_visible = false; - - // Fix rate control mode selection if ALL_INTRA is selected. - if (obs_data_get_int(settings, ST_KEY_ENCODER_USAGE) == AOM_USAGE_ALL_INTRA) { - obs_data_set_int(settings, ST_KEY_RATECONTROL_MODE, static_cast(aom_rc_mode::AOM_Q)); - } - - { // Based on the Rate Control Mode, show and hide options. - auto mode = static_cast(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE)); - if (mode == AOM_CBR) { - is_bitrate_visible = true; - is_overundershoot_visible = true; - } else if (mode == AOM_VBR) { - is_bitrate_visible = true; - is_overundershoot_visible = true; - } else if (mode == AOM_CQ) { - is_bitrate_visible = true; - is_overundershoot_visible = true; - is_quality_visible = true; - } else if (mode == AOM_Q) { - is_quality_visible = true; - } - - obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BITRATE), is_bitrate_visible); - obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT), - is_overundershoot_visible); - obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BITRATE_OVERSHOOT), - is_overundershoot_visible); -#ifdef AOM_CTRL_AOME_SET_CQ_LEVEL - obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_QUALITY), is_quality_visible); -#endif - } - return true; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return false; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return false; - } -} - -static bool modified_keyframes(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept -{ - try { - bool is_seconds = obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVALTYPE) == 0; - obs_property_set_visible(obs_properties_get(props, ST_KEY_KEYFRAMES_INTERVAL_FRAMES), !is_seconds); - obs_property_set_visible(obs_properties_get(props, ST_KEY_KEYFRAMES_INTERVAL_SECONDS), is_seconds); - return true; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return false; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return false; - } -} - -obs_properties_t* aom_av1_factory::get_properties2(instance_t* data) -{ - obs_properties_t* props = obs_properties_create(); - - { - auto p = obs_properties_add_text(props, "[[deprecated]]", D_TRANSLATE(ST_I18N_DEPRECATED), OBS_TEXT_INFO); - obs_property_text_set_info_type(p, OBS_TEXT_INFO_WARNING); - obs_property_text_set_info_word_wrap(p, true); - } - -#ifdef ENABLE_FRONTEND - { - obs_properties_add_button2(props, S_MANUAL_OPEN, D_TRANSLATE(S_MANUAL_OPEN), aom_av1_factory::on_manual_open, - this); - } -#endif - - { // Presets - obs_properties_t* grp = obs_properties_create(); - obs_properties_add_group(props, ST_I18N_ENCODER, D_TRANSLATE(ST_I18N_ENCODER), OBS_GROUP_NORMAL, grp); - //obs_properties_add_group(props, S_CODEC_AV1, D_TRANSLATE(S_CODEC_AV1), OBS_GROUP_NORMAL, grp); - - { // Usage - auto p = obs_properties_add_list(grp, ST_KEY_ENCODER_USAGE, D_TRANSLATE(ST_I18N_ENCODER_USAGE), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_modified_callback(p, modified_usage); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_USAGE_GOODQUALITY), - static_cast(AOM_USAGE_GOOD_QUALITY)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_USAGE_REALTIME), - static_cast(AOM_USAGE_REALTIME)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_USAGE_ALLINTRA), - static_cast(AOM_USAGE_ALL_INTRA)); - } - -#ifdef AOM_CTRL_AOME_SET_CPUUSED - { // CPU Usage - auto p = obs_properties_add_list(grp, ST_KEY_ENCODER_CPUUSAGE, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_10), 10); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_9), 9); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_8), 8); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_7), 7); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_6), 6); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_5), 5); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_4), 4); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_3), 3); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_2), 2); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_1), 1); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ENCODER_CPUUSAGE_0), 0); - } -#endif - - { // Profile - auto p = obs_properties_add_list(grp, ST_KEY_ENCODER_PROFILE, D_TRANSLATE(S_CODEC_AV1_PROFILE), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), - static_cast(codec::av1::profile::UNKNOWN)); - obs_property_list_add_int(p, codec::av1::profile_to_string(codec::av1::profile::MAIN), - static_cast(codec::av1::profile::MAIN)); - obs_property_list_add_int(p, codec::av1::profile_to_string(codec::av1::profile::HIGH), - static_cast(codec::av1::profile::HIGH)); - obs_property_list_add_int(p, codec::av1::profile_to_string(codec::av1::profile::PROFESSIONAL), - static_cast(codec::av1::profile::PROFESSIONAL)); - } - } - - { // Rate Control Options - obs_properties_t* grp = obs_properties_create(); - obs_properties_add_group(props, ST_I18N_RATECONTROL, D_TRANSLATE(ST_I18N_RATECONTROL), OBS_GROUP_NORMAL, grp); - - { // Mode - auto p = obs_properties_add_list(grp, ST_KEY_RATECONTROL_MODE, D_TRANSLATE(ST_I18N_RATECONTROL_MODE), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_modified_callback(p, modified_ratecontrol_mode); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_RATECONTROL_MODE_VBR), static_cast(AOM_VBR)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_RATECONTROL_MODE_CBR), static_cast(AOM_CBR)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_RATECONTROL_MODE_CQ), static_cast(AOM_CQ)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_RATECONTROL_MODE_Q), static_cast(AOM_Q)); - } - - { // Look-Ahead - auto p = - obs_properties_add_int(grp, ST_KEY_RATECONTROL_LOOKAHEAD, D_TRANSLATE(ST_I18N_RATECONTROL_LOOKAHEAD), - -1, std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " frames"); - } - - { // Limits - obs_properties_t* grp2 = obs_properties_create(); - obs_properties_add_group(grp, ST_I18N_RATECONTROL_LIMITS, D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS), - OBS_GROUP_NORMAL, grp2); - - { // Bitrate - auto p = obs_properties_add_int(grp2, ST_KEY_RATECONTROL_LIMITS_BITRATE, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BITRATE), 0, - std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " kbit/s"); - } - - { // Bitrate Under/Overshoot - auto p1 = obs_properties_add_int_slider(grp2, ST_KEY_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BITRATE_UNDERSHOOT), -1, - 100, 1); - auto p2 = obs_properties_add_int_slider(grp2, ST_KEY_RATECONTROL_LIMITS_BITRATE_OVERSHOOT, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BITRATE_OVERSHOOT), -1, - 100, 1); - obs_property_float_set_suffix(p1, " %"); - obs_property_float_set_suffix(p2, " %"); - } - -#ifdef AOM_CTRL_AOME_SET_CQ_LEVEL - { // Quality - auto p = obs_properties_add_int_slider(grp2, ST_KEY_RATECONTROL_LIMITS_QUALITY, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_QUALITY), -1, 63, 1); - } -#endif - - { // Quantizer - auto p1 = - obs_properties_add_int_slider(grp2, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MINIMUM, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_QUANTIZER_MINIMUM), -1, 63, 1); - auto p2 = - obs_properties_add_int_slider(grp2, ST_KEY_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM, - D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_QUANTIZER_MAXIMUM), -1, 63, 1); - } - } - - { // Buffer - obs_properties_t* grp2 = obs_properties_create(); - obs_properties_add_group(grp, ST_I18N_RATECONTROL_BUFFER, D_TRANSLATE(ST_I18N_RATECONTROL_BUFFER), - OBS_GROUP_NORMAL, grp2); - - { // Buffer Size - auto p = obs_properties_add_int(grp2, ST_KEY_RATECONTROL_BUFFER_SIZE, - D_TRANSLATE(ST_I18N_RATECONTROL_BUFFER_SIZE), -1, - std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " ms"); - } - - { // Initial Buffer Size - auto p = obs_properties_add_int(grp2, ST_KEY_RATECONTROL_BUFFER_SIZE_INITIAL, - D_TRANSLATE(ST_I18N_RATECONTROL_BUFFER_SIZE_INITIAL), -1, - std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " ms"); - } - - { // Optimal Buffer Size - auto p = obs_properties_add_int(grp2, ST_KEY_RATECONTROL_BUFFER_SIZE_OPTIMAL, - D_TRANSLATE(ST_I18N_RATECONTROL_BUFFER_SIZE_OPTIMAL), -1, - std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " ms"); - } - } - } - - { // Key-Frame Options - obs_properties_t* grp = obs_properties_create(); - obs_properties_add_group(props, ST_I18N_KEYFRAMES, D_TRANSLATE(ST_I18N_KEYFRAMES), OBS_GROUP_NORMAL, grp); - - { // Key-Frame Interval Type - auto p = - obs_properties_add_list(grp, ST_KEY_KEYFRAMES_INTERVALTYPE, D_TRANSLATE(ST_I18N_KEYFRAMES_INTERVALTYPE), - OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_modified_callback(p, modified_keyframes); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_KEYFRAMES_INTERVALTYPE_SECONDS), 0); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_KEYFRAMES_INTERVALTYPE_FRAMES), 1); - } - - { // Key-Frame Interval Seconds - auto p = obs_properties_add_float(grp, ST_KEY_KEYFRAMES_INTERVAL_SECONDS, - D_TRANSLATE(ST_I18N_KEYFRAMES_INTERVAL), 0.00, - std::numeric_limits::max(), 0.01); - obs_property_float_set_suffix(p, " seconds"); - } - - { // Key-Frame Interval Frames - auto p = - obs_properties_add_int(grp, ST_KEY_KEYFRAMES_INTERVAL_FRAMES, D_TRANSLATE(ST_I18N_KEYFRAMES_INTERVAL), - 0, std::numeric_limits::max(), 1); - obs_property_int_set_suffix(p, " frames"); - } - } - - { // Advanced Options - obs_properties_t* grp = obs_properties_create(); - obs_properties_add_group(props, ST_I18N_ADVANCED, D_TRANSLATE(ST_I18N_ADVANCED), OBS_GROUP_NORMAL, grp); - - { // Threads - auto p = obs_properties_add_int(grp, ST_KEY_ADVANCED_THREADS, D_TRANSLATE(ST_I18N_ADVANCED_THREADS), 0, - std::numeric_limits::max(), 1); - } - -#ifdef AOM_CTRL_AV1E_SET_ROW_MT - { // Row-MT - auto p = streamfx::util::obs_properties_add_tristate(grp, ST_KEY_ADVANCED_ROWMULTITHREADING, - D_TRANSLATE(ST_I18N_ADVANCED_ROWMULTITHREADING)); - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_TILE_COLUMNS - { // Tile Columns - auto p = obs_properties_add_int_slider(grp, ST_KEY_ADVANCED_TILE_COLUMNS, - D_TRANSLATE(ST_I18N_ADVANCED_TILE_COLUMNS), -1, 6, 1); - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_TILE_ROWS - { // Tile Rows - auto p = obs_properties_add_int_slider(grp, ST_KEY_ADVANCED_TILE_ROWS, - D_TRANSLATE(ST_I18N_ADVANCED_TILE_ROWS), -1, 6, 1); - } -#endif - { - obs_properties_t* grp2 = obs_properties_create(); - obs_properties_add_group(grp, ST_I18N_ADVANCED_TUNE, D_TRANSLATE(ST_I18N_ADVANCED_TUNE), OBS_GROUP_NORMAL, - grp2); - -#ifdef AOM_CTRL_AOME_SET_TUNING - { // Tuning - auto p = obs_properties_add_list(grp2, ST_KEY_ADVANCED_TUNE_METRIC, - D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC), OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_PSNR), - static_cast(AOM_TUNE_PSNR)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_SSIM), - static_cast(AOM_TUNE_SSIM)); -#ifdef _DEBUG - // These have no actual use outside of debug builds, way too slow! - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_VMAFWITHPREPROCESSING), - static_cast(AOM_TUNE_VMAF_WITH_PREPROCESSING)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_VMAFWITHOUTPREPROCESSING), - static_cast(AOM_TUNE_VMAF_WITHOUT_PREPROCESSING)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_VMAFMAXGAIN), - static_cast(AOM_TUNE_VMAF_MAX_GAIN)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_VMAFNEGMAXGAIN), - static_cast(AOM_TUNE_VMAF_NEG_MAX_GAIN)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_METRIC_BUTTERAUGLI), - static_cast(AOM_TUNE_BUTTERAUGLI)); -#endif - } -#endif - -#ifdef AOM_CTRL_AV1E_SET_TUNE_CONTENT - { // Content Tuning - auto p = obs_properties_add_list(grp2, ST_KEY_ADVANCED_TUNE_CONTENT, - D_TRANSLATE(ST_I18N_ADVANCED_TUNE_CONTENT), OBS_COMBO_TYPE_LIST, - OBS_COMBO_FORMAT_INT); - obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast(AOM_CONTENT_DEFAULT)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_CONTENT_SCREEN), - static_cast(AOM_CONTENT_SCREEN)); - obs_property_list_add_int(p, D_TRANSLATE(ST_I18N_ADVANCED_TUNE_CONTENT_FILM), - static_cast(AOM_CONTENT_FILM)); - } -#endif - } - } - - return props; -} - -#ifdef ENABLE_FRONTEND -bool aom_av1_factory::on_manual_open(obs_properties_t* props, obs_property_t* property, void* data) -{ - streamfx::open_url(HELP_URL); - return false; -} -#endif diff --git a/source/encoders/encoder-aom-av1.hpp b/source/encoders/encoder-aom-av1.hpp deleted file mode 100644 index 597ae8cc..00000000 --- a/source/encoders/encoder-aom-av1.hpp +++ /dev/null @@ -1,191 +0,0 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2021-2023 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END - -//--------------------------------------------------------------------------------// -// THIS FEATURE IS DEPRECATED. SUBMITTED PATCHES WILL BE REJECTED. -//--------------------------------------------------------------------------------// - -#pragma once -#include "common.hpp" -#include "encoders/codecs/av1.hpp" -#include "obs/obs-encoder-factory.hpp" -#include "util/util-library.hpp" -#include "util/util-profiler.hpp" - -#include "warning-disable.hpp" -#include -#include -#include "warning-enable.hpp" - -extern "C" { -#include "warning-disable.hpp" -#include -#include "warning-enable.hpp" -}; - -namespace streamfx::encoder::aom::av1 { - class aom_av1_factory; - - class aom_av1_instance : public obs::encoder_instance { - std::shared_ptr _factory; - - aom_codec_iface_t* _iface; - aom_codec_ctx_t _ctx; - aom_codec_enc_cfg_t _cfg; - size_t _image_index; - std::vector _images; - aom_fixed_buf_t* _global_headers; - - bool _initialized; - struct { - // Video (All Static) - uint16_t width; - uint16_t height; - struct { - uint32_t num; - uint32_t den; - } fps; - - // Color (All Static) - aom_img_fmt color_format; - aom_color_primaries_t color_primaries; - aom_transfer_characteristics_t color_trc; - aom_matrix_coefficients_t color_matrix; - aom_color_range_t color_range; - bool monochrome; - - // Encoder - codec::av1::profile profile; // Static - int8_t preset; - - // Rate Control - aom_rc_mode rc_mode; // Static - int8_t rc_lookahead; // Static - int32_t rc_bitrate; - int32_t rc_bitrate_overshoot; - int32_t rc_bitrate_undershoot; - int8_t rc_quality; - int8_t rc_quantizer_min; - int8_t rc_quantizer_max; - int32_t rc_buffer_ms; - int32_t rc_buffer_initial_ms; - int32_t rc_buffer_optimal_ms; - - // Key-Frames - aom_kf_mode kf_mode; - int32_t kf_distance_min; - int32_t kf_distance_max; - - // Threads and Tiling (All Static) - int8_t threads; - int8_t rowmultithreading; - int8_t tile_columns; - int8_t tile_rows; - aom_tune_metric tune_metric; - aom_tune_content tune_content; - } _settings; - -#ifdef ENABLE_PROFILING - std::shared_ptr _profiler_copy; - std::shared_ptr _profiler_encode; - std::shared_ptr _profiler_packet; -#endif - - public: - aom_av1_instance(obs_data_t* settings, obs_encoder_t* self, bool is_hw); - virtual ~aom_av1_instance(); - - virtual void migrate(obs_data_t* settings, uint64_t version); - - virtual bool update(obs_data_t* settings); - - void log(); - - virtual bool get_extra_data(uint8_t** extra_data, size_t* size); - - virtual bool get_sei_data(uint8_t** sei_data, size_t* size); - - virtual void get_video_info(struct video_scale_info* info); - - virtual bool encode_video(encoder_frame* frame, encoder_packet* packet, bool* received_packet); - }; - - class aom_av1_factory : public obs::encoder_factory { - std::shared_ptr<::streamfx::util::library> _library; - - public: - aom_av1_factory(); - ~aom_av1_factory(); - - const char* get_name() override; - - void* create(obs_data_t* settings, obs_encoder_t* encoder, bool is_hw) override; - - void get_defaults2(obs_data_t* data) override; - - obs_properties_t* get_properties2(instance_t* data) override; - -#ifdef ENABLE_FRONTEND - static bool on_manual_open(obs_properties_t* props, obs_property_t* property, void* data); -#endif - - public: - // aom_codec.h - decltype(&aom_codec_version) libaom_codec_version; - decltype(&aom_codec_version_str) libaom_codec_version_str; - decltype(&aom_codec_version_extra_str) libaom_codec_version_extra_str; - decltype(&aom_codec_build_config) libaom_codec_build_config; - decltype(&aom_codec_iface_name) libaom_codec_iface_name; - decltype(&aom_codec_err_to_string) libaom_codec_err_to_string; - decltype(&aom_codec_error) libaom_codec_error; - decltype(&aom_codec_error_detail) libaom_codec_error_detail; - decltype(&aom_codec_destroy) libaom_codec_destroy; - decltype(&aom_codec_get_caps) libaom_codec_get_caps; - decltype(&aom_codec_control) libaom_codec_control; - decltype(&aom_codec_set_option) libaom_codec_set_option; - decltype(&aom_obu_type_to_string) libaom_obu_type_to_string; - - // aom_integer.h - decltype(&aom_uleb_size_in_bytes) libaom_uleb_size_in_bytes; - decltype(&aom_uleb_decode) libaom_uleb_decode; - decltype(&aom_uleb_encode) libaom_uleb_encode; - decltype(&aom_uleb_encode_fixed_size) libaom_uleb_encode_fixed_size; - - // aom_image.h - decltype(&aom_img_alloc) libaom_img_alloc; - decltype(&aom_img_wrap) libaom_img_wrap; - decltype(&aom_img_alloc_with_border) libaom_img_alloc_with_border; - decltype(&aom_img_set_rect) libaom_img_set_rect; - decltype(&aom_img_flip) libaom_img_flip; - decltype(&aom_img_free) libaom_img_free; - decltype(&aom_img_plane_width) libaom_img_plane_width; - decltype(&aom_img_plane_height) libaom_img_plane_height; - decltype(&aom_img_add_metadata) libaom_img_add_metadata; - decltype(&aom_img_get_metadata) libaom_img_get_metadata; - decltype(&aom_img_num_metadata) libaom_img_num_metadata; - decltype(&aom_img_remove_metadata) libaom_img_remove_metadata; - decltype(&aom_img_metadata_alloc) libaom_img_metadata_alloc; - decltype(&aom_img_metadata_free) libaom_img_metadata_free; - - // aom_encoder.h - decltype(&aom_codec_enc_init_ver) libaom_codec_enc_init_ver; - decltype(&aom_codec_enc_config_default) libaom_codec_enc_config_default; - decltype(&aom_codec_enc_config_set) libaom_codec_enc_config_set; - decltype(&aom_codec_get_global_headers) libaom_codec_get_global_headers; - decltype(&aom_codec_encode) libaom_codec_encode; - decltype(&aom_codec_set_cx_data_buf) libaom_codec_set_cx_data_buf; - decltype(&aom_codec_get_cx_data) libaom_codec_get_cx_data; - decltype(&aom_codec_get_preview_frame) libaom_codec_get_preview_frame; - - // aomcx.h - decltype(&aom_codec_av1_cx) libaom_codec_av1_cx; - - public: // Singleton - static void initialize(); - - static void finalize(); - - static std::shared_ptr get(); - }; -} // namespace streamfx::encoder::aom::av1 diff --git a/source/plugin.cpp b/source/plugin.cpp index c47b2692..90444ed2 100644 --- a/source/plugin.cpp +++ b/source/plugin.cpp @@ -12,14 +12,6 @@ #include "nvidia/cuda/nvidia-cuda-obs.hpp" #endif -#ifdef ENABLE_ENCODER_AOM_AV1 -#include "encoders/encoder-aom-av1.hpp" -#endif - -#ifdef ENABLE_FILTER_DISPLACEMENT -#include "filters/filter-displacement.hpp" -#endif - #ifdef ENABLE_FRONTEND #include "ui/ui.hpp" #endif @@ -110,20 +102,6 @@ MODULE_EXPORT bool obs_module_load(void) } #endif - // Encoders - { -#ifdef ENABLE_ENCODER_AOM_AV1 - streamfx::encoder::aom::av1::aom_av1_factory::initialize(); -#endif - } - - // Filters - { -#ifdef ENABLE_FILTER_DISPLACEMENT - streamfx::filter::displacement::displacement_factory::initialize(); -#endif - } - DLOG_INFO("Loaded Version %s", STREAMFX_VERSION_STRING); return true; } catch (std::exception const& ex) { @@ -140,20 +118,6 @@ MODULE_EXPORT void obs_module_unload(void) try { DLOG_INFO("Unloading Version %s", STREAMFX_VERSION_STRING); - // Filters - { -#ifdef ENABLE_FILTER_DISPLACEMENT - streamfx::filter::displacement::displacement_factory::finalize(); -#endif - } - - // Encoders - { -#ifdef ENABLE_ENCODER_AOM_AV1 - streamfx::encoder::aom::av1::aom_av1_factory::finalize(); -#endif - } - // Finalize GLAD (OpenGL) { streamfx::obs::gs::context gctx{};