code: Migrate encoder::ffmpeg::nvenc to new loader
This commit is contained in:
parent
51282b7b85
commit
1c76169821
|
@ -1171,12 +1171,8 @@ if(T_CHECK)
|
|||
is_feature_enabled(ENCODER_FFMPEG_NVENC T_CHECK)
|
||||
if(T_CHECK)
|
||||
list(APPEND PROJECT_PRIVATE_SOURCE
|
||||
"source/encoders/ffmpeg/nvenc_shared.hpp"
|
||||
"source/encoders/ffmpeg/nvenc_shared.cpp"
|
||||
"source/encoders/ffmpeg/nvenc_h264_handler.hpp"
|
||||
"source/encoders/ffmpeg/nvenc_h264_handler.cpp"
|
||||
"source/encoders/ffmpeg/nvenc_hevc_handler.hpp"
|
||||
"source/encoders/ffmpeg/nvenc_hevc_handler.cpp"
|
||||
"source/encoders/ffmpeg/nvenc.hpp"
|
||||
"source/encoders/ffmpeg/nvenc.cpp"
|
||||
)
|
||||
list(APPEND PROJECT_DEFINITIONS
|
||||
ENABLE_ENCODER_FFMPEG_NVENC
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// Copyright (C) 2022 lainon <GermanAizek@yandex.ru>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#include "nvenc_shared.hpp"
|
||||
#include "nvenc.hpp"
|
||||
#include "common.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "encoders/codecs/h264.hpp"
|
||||
#include "encoders/codecs/hevc.hpp"
|
||||
#include "encoders/encoder-ffmpeg.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
extern "C" {
|
||||
#include <libavutil/opt.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
#include "warning-enable.hpp"
|
||||
|
||||
#define ST_I18N_PRESET "Encoder.FFmpeg.NVENC.Preset"
|
||||
#define ST_I18N_PRESET_(x) ST_I18N_PRESET "." D_VSTR(x)
|
||||
|
@ -77,7 +82,15 @@ extern "C" {
|
|||
#define ST_I18N_OTHER_LOWDELAYKEYFRAMESCALE ST_I18N_OTHER ".LowDelayKeyFrameScale"
|
||||
#define ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE "Other.LowDelayKeyFrameScale"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
#define ST_KEY_H264_PROFILE "H264.Profile"
|
||||
#define ST_KEY_H264_LEVEL "H264.Level"
|
||||
|
||||
#define ST_KEY_H265_PROFILE "H265.Profile"
|
||||
#define ST_KEY_H265_TIER "H265.Tier"
|
||||
#define ST_KEY_H264_LEVEL "H265.Level"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg;
|
||||
using namespace streamfx::encoder::codec;
|
||||
|
||||
inline bool is_cqp(std::string_view rc)
|
||||
{
|
||||
|
@ -94,7 +107,7 @@ inline bool is_vbr(std::string_view rc)
|
|||
return std::string_view("vbr") == rc;
|
||||
}
|
||||
|
||||
bool streamfx::encoder::ffmpeg::handler::nvenc::is_available()
|
||||
bool nvenc::is_available()
|
||||
{
|
||||
#if defined(D_PLATFORM_WINDOWS)
|
||||
#if defined(D_PLATFORM_64BIT)
|
||||
|
@ -113,37 +126,7 @@ bool streamfx::encoder::ffmpeg::handler::nvenc::is_available()
|
|||
}
|
||||
}
|
||||
|
||||
void nvenc::override_update(ffmpeg_instance* instance, obs_data_t*)
|
||||
{
|
||||
AVCodecContext* context = const_cast<AVCodecContext*>(instance->get_avcodeccontext());
|
||||
|
||||
int64_t rclookahead = 0;
|
||||
int64_t surfaces = 0;
|
||||
int64_t async_depth = 0;
|
||||
|
||||
av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rclookahead);
|
||||
av_opt_get_int(context, "surfaces", AV_OPT_SEARCH_CHILDREN, &surfaces);
|
||||
av_opt_get_int(context, "async_depth", AV_OPT_SEARCH_CHILDREN, &async_depth);
|
||||
|
||||
// Calculate and set the number of surfaces to allocate (if not user overridden).
|
||||
if (surfaces == 0) {
|
||||
surfaces = std::max<int64_t>(4ll, (context->max_b_frames + 1ll) * 4ll);
|
||||
if (rclookahead > 0) {
|
||||
surfaces = std::max<int64_t>(1ll, std::max<int64_t>(surfaces, rclookahead + (context->max_b_frames + 5ll)));
|
||||
} else if (context->max_b_frames > 0) {
|
||||
surfaces = std::max<int64_t>(4ll, (context->max_b_frames + 1ll) * 4ll);
|
||||
} else {
|
||||
surfaces = 4;
|
||||
}
|
||||
|
||||
av_opt_set_int(context, "surfaces", surfaces, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
// Set delay
|
||||
context->delay = std::min<int>(std::max<int>(static_cast<int>(async_depth), 3), static_cast<int>(surfaces - 1));
|
||||
}
|
||||
|
||||
void nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
|
||||
void nvenc::defaults(ffmpeg_factory* factory, obs_data_t* settings)
|
||||
{
|
||||
obs_data_set_default_string(settings, ST_KEY_PRESET, "default");
|
||||
obs_data_set_default_string(settings, ST_I18N_TUNE, "hq");
|
||||
|
@ -232,8 +215,10 @@ static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* se
|
|||
return true;
|
||||
}
|
||||
|
||||
void nvenc::get_properties_pre(obs_properties_t* props, const AVCodec*, const AVCodecContext* context)
|
||||
void nvenc::properties_before(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props, AVCodecContext* context)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(props, ST_KEY_PRESET, D_TRANSLATE(ST_I18N_PRESET), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "preset", [&p](const AVOption* opt) {
|
||||
|
@ -253,8 +238,10 @@ void nvenc::get_properties_pre(obs_properties_t* props, const AVCodec*, const AV
|
|||
}
|
||||
}
|
||||
|
||||
void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context)
|
||||
void nvenc::properies_after(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props, AVCodecContext* context)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
|
||||
{ // Rate Control
|
||||
obs_properties_t* grp = props;
|
||||
if (!streamfx::util::are_property_groups_broken()) {
|
||||
|
@ -420,7 +407,7 @@ void nvenc::get_properties_post(obs_properties_t* props, const AVCodec* codec, c
|
|||
}
|
||||
}
|
||||
|
||||
void nvenc::get_runtime_properties(obs_properties_t* props, const AVCodec*, AVCodecContext*)
|
||||
void nvenc::properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
obs_property_set_enabled(obs_properties_get(props, ST_KEY_PRESET), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, ST_KEY_TUNE), false);
|
||||
|
@ -456,8 +443,94 @@ void nvenc::get_runtime_properties(obs_properties_t* props, const AVCodec*, AVCo
|
|||
obs_property_set_enabled(obs_properties_get(props, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE), false);
|
||||
}
|
||||
|
||||
void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
void nvenc::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version)
|
||||
{
|
||||
// Only test for A.B.C in A.B.C.D
|
||||
version = version & STREAMFX_MASK_UPDATE;
|
||||
|
||||
#define COPY_UNSET(TYPE, FROM, TO) \
|
||||
if (obs_data_has_user_value(settings, FROM)) { \
|
||||
obs_data_set_##TYPE(settings, TO, obs_data_get_##TYPE(settings, FROM)); \
|
||||
obs_data_unset_user_value(settings, FROM); \
|
||||
}
|
||||
|
||||
if (version <= STREAMFX_MAKE_VERSION(0, 8, 0, 0)) {
|
||||
COPY_UNSET(int, "RateControl.Bitrate.Target", ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET);
|
||||
COPY_UNSET(int, "RateControl.Bitrate.Maximum", ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET);
|
||||
COPY_UNSET(int, "RateControl.BufferSize", ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE);
|
||||
COPY_UNSET(int, "RateControl.Quality.Minimum", ST_KEY_RATECONTROL_QP_MINIMUM);
|
||||
COPY_UNSET(int, "RateControl.Quality.Maximum", ST_KEY_RATECONTROL_QP_MAXIMUM);
|
||||
COPY_UNSET(double, "RateControl.Quality.Target", ST_KEY_RATECONTROL_LIMITS_QUALITY);
|
||||
}
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 0, 0)) {
|
||||
obs_data_unset_user_value(settings, "Other.AccessUnitDelimiter");
|
||||
obs_data_unset_user_value(settings, "Other.DecodedPictureBufferSize");
|
||||
}
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
|
||||
// Preset
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_PRESET); v != -1) {
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "default"}, {1, "slow"}, {2, "medium"}, {3, "fast"}, {4, "hp"}, {5, "hq"}, {6, "bd"}, {7, "ll"}, {8, "llhq"}, {9, "llhp"}, {10, "lossless"}, {11, "losslesshp"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_PRESET, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Rate Control Mode
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_RATECONTROL_MODE))
|
||||
v = 4;
|
||||
|
||||
switch (v) {
|
||||
case 0: // CQP
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "constqp");
|
||||
break;
|
||||
case 2: // VBR_HQ
|
||||
obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1);
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MULTIPASS, "qres");
|
||||
case 1: // VBR
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "vbr");
|
||||
break;
|
||||
case 5: // CBR_LD_HQ
|
||||
obs_data_set_int(settings, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE, 1);
|
||||
case 4: // CBR_HQ
|
||||
obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1);
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MULTIPASS, "qres");
|
||||
case 3: // CBR
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "cbr");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Target Quality
|
||||
if (auto v = obs_data_get_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY); v > 0) {
|
||||
obs_data_set_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY, (v / 100.) * 51.);
|
||||
}
|
||||
|
||||
// B-Frame Reference Modes
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE); v != -1) {
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "default"},
|
||||
{1, "each"},
|
||||
{2, "middle"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE, k->second.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef COPY_UNSET
|
||||
}
|
||||
|
||||
void nvenc::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_PRESET); !context->internal && (v != nullptr) && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "preset", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
@ -667,8 +740,41 @@ void nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* c
|
|||
}
|
||||
}
|
||||
|
||||
void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* context)
|
||||
void nvenc::override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
AVCodecContext* context = const_cast<AVCodecContext*>(instance->get_avcodeccontext());
|
||||
|
||||
int64_t rclookahead = 0;
|
||||
int64_t surfaces = 0;
|
||||
int64_t async_depth = 0;
|
||||
|
||||
av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rclookahead);
|
||||
av_opt_get_int(context, "surfaces", AV_OPT_SEARCH_CHILDREN, &surfaces);
|
||||
av_opt_get_int(context, "async_depth", AV_OPT_SEARCH_CHILDREN, &async_depth);
|
||||
|
||||
// Calculate and set the number of surfaces to allocate (if not user overridden).
|
||||
if (surfaces == 0) {
|
||||
surfaces = std::max<int64_t>(4ll, (context->max_b_frames + 1ll) * 4ll);
|
||||
if (rclookahead > 0) {
|
||||
surfaces = std::max<int64_t>(1ll, std::max<int64_t>(surfaces, rclookahead + (context->max_b_frames + 5ll)));
|
||||
} else if (context->max_b_frames > 0) {
|
||||
surfaces = std::max<int64_t>(4ll, (context->max_b_frames + 1ll) * 4ll);
|
||||
} else {
|
||||
surfaces = 4;
|
||||
}
|
||||
|
||||
av_opt_set_int(context, "surfaces", surfaces, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
// Set delay
|
||||
context->delay = std::min<int>(std::max<int>(static_cast<int>(async_depth), 3), static_cast<int>(surfaces - 1));
|
||||
}
|
||||
|
||||
void nvenc::log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
using namespace ::streamfx::ffmpeg;
|
||||
|
||||
DLOG_INFO("[%s] NVIDIA NVENC:", codec->name);
|
||||
|
@ -729,85 +835,364 @@ void nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* conte
|
|||
tools::print_av_option_bool(context, "constrained-encoding", " Constrained Encoding");
|
||||
}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::nvenc::migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context)
|
||||
// H264/AVC Handler
|
||||
//-------------------
|
||||
|
||||
nvenc_h264::nvenc_h264() : handler("h264_nvenc"){};
|
||||
|
||||
nvenc_h264::~nvenc_h264(){};
|
||||
|
||||
bool nvenc_h264::has_keyframes(ffmpeg_factory*)
|
||||
{
|
||||
// Only test for A.B.C in A.B.C.D
|
||||
version = version & STREAMFX_MASK_UPDATE;
|
||||
|
||||
#define COPY_UNSET(TYPE, FROM, TO) \
|
||||
if (obs_data_has_user_value(settings, FROM)) { \
|
||||
obs_data_set_##TYPE(settings, TO, obs_data_get_##TYPE(settings, FROM)); \
|
||||
obs_data_unset_user_value(settings, FROM); \
|
||||
return true;
|
||||
}
|
||||
|
||||
if (version <= STREAMFX_MAKE_VERSION(0, 8, 0, 0)) {
|
||||
COPY_UNSET(int, "RateControl.Bitrate.Target", ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET);
|
||||
COPY_UNSET(int, "RateControl.Bitrate.Maximum", ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET);
|
||||
COPY_UNSET(int, "RateControl.BufferSize", ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE);
|
||||
COPY_UNSET(int, "RateControl.Quality.Minimum", ST_KEY_RATECONTROL_QP_MINIMUM);
|
||||
COPY_UNSET(int, "RateControl.Quality.Maximum", ST_KEY_RATECONTROL_QP_MAXIMUM);
|
||||
COPY_UNSET(double, "RateControl.Quality.Target", ST_KEY_RATECONTROL_LIMITS_QUALITY);
|
||||
bool nvenc_h264::has_threading(ffmpeg_factory*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 0, 0)) {
|
||||
obs_data_unset_user_value(settings, "Other.AccessUnitDelimiter");
|
||||
obs_data_unset_user_value(settings, "Other.DecodedPictureBufferSize");
|
||||
bool nvenc_h264::is_hardware(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_h264::is_reconfigurable(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes)
|
||||
{
|
||||
threads = false;
|
||||
gpu = false;
|
||||
keyframes = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void nvenc_h264::adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec)
|
||||
{
|
||||
name = "NVIDIA NVENC H.264/AVC (via FFmpeg)";
|
||||
if (!nvenc::is_available()) // If we don't have NVENC, don't even allow listing it.
|
||||
factory->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED | OBS_ENCODER_CAP_INTERNAL;
|
||||
}
|
||||
|
||||
void nvenc_h264::defaults(ffmpeg_factory* factory, obs_data_t* settings)
|
||||
{
|
||||
nvenc::defaults(factory, settings);
|
||||
|
||||
obs_data_set_default_string(settings, ST_KEY_H264_PROFILE, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_H264_LEVEL, "auto");
|
||||
}
|
||||
|
||||
void nvenc_h264::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
if (!instance) {
|
||||
this->properties_encoder(factory, instance, props);
|
||||
} else {
|
||||
this->properties_runtime(factory, instance, props);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_h264::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version)
|
||||
{
|
||||
nvenc::migrate(factory, instance, settings, version);
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
|
||||
// Preset
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_PRESET); v != -1) {
|
||||
// Profile
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_H264_PROFILE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_H264_PROFILE))
|
||||
v = 3;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "default"}, {1, "slow"}, {2, "medium"}, {3, "fast"}, {4, "hp"}, {5, "hq"}, {6, "bd"}, {7, "ll"}, {8, "llhq"}, {9, "llhp"}, {10, "lossless"}, {11, "losslesshp"},
|
||||
{0, "baseline"}, {1, "baseline"}, {2, "main"}, {3, "high"}, {4, "high444p"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_PRESET, k->second.data());
|
||||
obs_data_set_string(settings, ST_KEY_H264_PROFILE, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Rate Control Mode
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_RATECONTROL_MODE))
|
||||
v = 4;
|
||||
|
||||
switch (v) {
|
||||
case 0: // CQP
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "constqp");
|
||||
break;
|
||||
case 2: // VBR_HQ
|
||||
obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1);
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MULTIPASS, "qres");
|
||||
case 1: // VBR
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "vbr");
|
||||
break;
|
||||
case 5: // CBR_LD_HQ
|
||||
obs_data_set_int(settings, ST_KEY_OTHER_LOWDELAYKEYFRAMESCALE, 1);
|
||||
case 4: // CBR_HQ
|
||||
obs_data_set_int(settings, ST_KEY_RATECONTROL_TWOPASS, 1);
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MULTIPASS, "qres");
|
||||
case 3: // CBR
|
||||
obs_data_set_string(settings, ST_KEY_RATECONTROL_MODE, "cbr");
|
||||
break;
|
||||
// Level
|
||||
obs_data_set_string(settings, ST_KEY_H264_LEVEL, "auto");
|
||||
}
|
||||
}
|
||||
|
||||
// Target Quality
|
||||
if (auto v = obs_data_get_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY); v > 0) {
|
||||
obs_data_set_double(settings, ST_KEY_RATECONTROL_LIMITS_QUALITY, (v / 100.) * 51.);
|
||||
void nvenc_h264::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
nvenc::update(factory, instance, settings);
|
||||
|
||||
if (!context->internal) {
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_H264_PROFILE); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "profile", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_H264_LEVEL); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// B-Frame Reference Modes
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE); v != -1) {
|
||||
void nvenc_h264::override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
nvenc::override_update(factory, instance, settings);
|
||||
}
|
||||
|
||||
void nvenc_h264::log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
nvenc::log(factory, instance, settings);
|
||||
|
||||
DLOG_INFO("[%s] H.264/AVC:", codec->name);
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "profile", " Profile", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "level", " Level", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void nvenc_h264::properties_encoder(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (!context->priv_data) {
|
||||
avcodec_free_context(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
nvenc::properties_before(factory, instance, props, context);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!streamfx::util::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, S_CODEC_H264, D_TRANSLATE(S_CODEC_H264), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_H264_PROFILE, D_TRANSLATE(S_CODEC_H264_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_DEFAULT), "");
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_H264_PROFILE, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_H264_LEVEL, D_TRANSLATE(S_CODEC_H264_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) {
|
||||
if (opt->default_val.i64 == 0) {
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_AUTOMATIC), "auto");
|
||||
} else {
|
||||
obs_property_list_add_string(p, opt->name, opt->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nvenc::properies_after(factory, instance, props, context);
|
||||
|
||||
if (context) {
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_h264::properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
nvenc::properties_runtime(factory, instance, props);
|
||||
}
|
||||
|
||||
static auto inst_h264 = nvenc_h264();
|
||||
|
||||
// H265/HEVC Handler
|
||||
//-------------------
|
||||
|
||||
nvenc_hevc::nvenc_hevc() : handler("hevc_nvenc"){};
|
||||
|
||||
nvenc_hevc::~nvenc_hevc(){};
|
||||
|
||||
bool nvenc_hevc::has_keyframes(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_hevc::has_threading(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nvenc_hevc::is_hardware(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_hevc::is_reconfigurable(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes)
|
||||
{
|
||||
threads = false;
|
||||
gpu = false;
|
||||
keyframes = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void nvenc_hevc::adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec)
|
||||
{
|
||||
name = "NVIDIA NVENC H.265/HEVC (via FFmpeg)";
|
||||
if (!nvenc::is_available())
|
||||
factory->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
|
||||
void nvenc_hevc::defaults(ffmpeg_factory* factory, obs_data_t* settings)
|
||||
{
|
||||
nvenc::defaults(factory, settings);
|
||||
|
||||
obs_data_set_default_string(settings, ST_KEY_H265_PROFILE, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_H265_TIER, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_H264_LEVEL, "auto");
|
||||
}
|
||||
|
||||
void nvenc_hevc::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
if (!instance) {
|
||||
this->properties_encoder(factory, instance, props);
|
||||
} else {
|
||||
this->properties_runtime(factory, instance, props);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version)
|
||||
{
|
||||
nvenc::migrate(factory, instance, settings, version);
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
|
||||
// Profile
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_H265_PROFILE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_H265_PROFILE))
|
||||
v = 0;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "default"},
|
||||
{1, "each"},
|
||||
{2, "middle"},
|
||||
{0, "main"},
|
||||
{1, "main10"},
|
||||
{2, "rext"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_OTHER_BFRAMEREFERENCEMODE, k->second.data());
|
||||
obs_data_set_string(settings, ST_KEY_H265_PROFILE, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Tier
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_H265_TIER); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_H265_TIER))
|
||||
v = 0;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "main"},
|
||||
{1, "high"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_H265_TIER, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Level
|
||||
obs_data_set_string(settings, ST_KEY_H264_LEVEL, "auto");
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
nvenc::update(factory, instance, settings);
|
||||
|
||||
if (!context->internal) {
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_H265_PROFILE); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "profile", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_H265_TIER); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "tier", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_H264_LEVEL); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef COPY_UNSET
|
||||
void nvenc_hevc::override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
nvenc::override_update(factory, instance, settings);
|
||||
}
|
||||
|
||||
void nvenc_hevc::log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
auto context = instance->get_avcodeccontext();
|
||||
|
||||
nvenc::log(factory, instance, settings);
|
||||
|
||||
DLOG_INFO("[%s] H.265/HEVC:", codec->name);
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "profile", " Profile", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "level", " Level", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "tier", " Tier", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void nvenc_hevc::properties_encoder(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
auto codec = factory->get_avcodec();
|
||||
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (!context->priv_data) {
|
||||
avcodec_free_context(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
nvenc::properties_before(factory, instance, props, context);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!streamfx::util::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, S_CODEC_HEVC, D_TRANSLATE(S_CODEC_HEVC), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_H265_PROFILE, D_TRANSLATE(S_CODEC_HEVC_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1);
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_HEVC_PROFILE, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_H265_TIER, D_TRANSLATE(S_CODEC_HEVC_TIER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1);
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "tier", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_HEVC_TIER, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_H264_LEVEL, D_TRANSLATE(S_CODEC_HEVC_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) {
|
||||
if (opt->default_val.i64 == 0) {
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_AUTOMATIC), "auto");
|
||||
} else {
|
||||
obs_property_list_add_string(p, opt->name, opt->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nvenc::properies_after(factory, instance, props, context);
|
||||
|
||||
if (context) {
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc::properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
|
||||
{
|
||||
nvenc::properties_runtime(factory, instance, props);
|
||||
}
|
||||
|
||||
static auto inst_hevc = nvenc_hevc();
|
|
@ -0,0 +1,95 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
|
||||
#pragma once
|
||||
#include "encoders/encoder-ffmpeg.hpp"
|
||||
#include "encoders/ffmpeg/handler.hpp"
|
||||
|
||||
#include "warning-disable.hpp"
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
#include "warning-enable.hpp"
|
||||
|
||||
/* NVENC has multiple compression modes:
|
||||
- CBR: Constant Bitrate (rc=cbr)
|
||||
- VBR: Variable Bitrate (rc=vbr)
|
||||
- CQP: Constant QP (rc=cqp)
|
||||
- CQ: Constant Quality (rc=vbr b=0 maxrate=0 qmin=0 qmax=51 cq=qp), this is basically CRF in X264.
|
||||
*/
|
||||
|
||||
namespace streamfx::encoder::ffmpeg {
|
||||
namespace nvenc {
|
||||
bool is_available();
|
||||
|
||||
void defaults(ffmpeg_factory* factory, obs_data_t* settings);
|
||||
void properties_before(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props, AVCodecContext* context);
|
||||
void properies_after(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props, AVCodecContext* context);
|
||||
void properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props);
|
||||
void migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version);
|
||||
void update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings);
|
||||
void override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings);
|
||||
void log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings);
|
||||
} // namespace nvenc
|
||||
|
||||
class nvenc_h264 : public handler {
|
||||
public:
|
||||
nvenc_h264();
|
||||
virtual ~nvenc_h264();
|
||||
|
||||
bool has_keyframes(ffmpeg_factory* factory) override;
|
||||
bool has_threading(ffmpeg_factory* factory) override;
|
||||
bool is_hardware(ffmpeg_factory* factory) override;
|
||||
bool is_reconfigurable(ffmpeg_factory* factory, bool& threads, bool& gpu, bool& keyframes) override;
|
||||
|
||||
void adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec) override;
|
||||
|
||||
std::string help(ffmpeg_factory* factory) override
|
||||
{
|
||||
return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg-NVENC";
|
||||
};
|
||||
|
||||
void defaults(ffmpeg_factory* factory, obs_data_t* settings) override;
|
||||
void properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) override;
|
||||
void migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version) override;
|
||||
void update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
void override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
void log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
|
||||
private:
|
||||
void properties_encoder(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props);
|
||||
void properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props);
|
||||
};
|
||||
|
||||
class nvenc_hevc : public handler {
|
||||
public:
|
||||
nvenc_hevc();
|
||||
virtual ~nvenc_hevc();
|
||||
|
||||
bool has_keyframes(ffmpeg_factory* factory) override;
|
||||
bool has_threading(ffmpeg_factory* factory) override;
|
||||
bool is_hardware(ffmpeg_factory* factory) override;
|
||||
bool is_reconfigurable(ffmpeg_factory* factory, bool& threads, bool& gpu, bool& keyframes) override;
|
||||
|
||||
void adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec) override;
|
||||
|
||||
std::string help(ffmpeg_factory* factory) override
|
||||
{
|
||||
return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg-NVENC";
|
||||
};
|
||||
|
||||
void defaults(ffmpeg_factory* factory, obs_data_t* settings) override;
|
||||
void properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) override;
|
||||
void migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version) override;
|
||||
void update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
void override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
void log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
|
||||
private:
|
||||
void properties_encoder(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props);
|
||||
void properties_runtime(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props);
|
||||
};
|
||||
} // namespace streamfx::encoder::ffmpeg
|
|
@ -1,179 +0,0 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// Copyright (C) 2022 lainon <GermanAizek@yandex.ru>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#include "nvenc_h264_handler.hpp"
|
||||
#include "common.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "../codecs/h264.hpp"
|
||||
#include "../encoder-ffmpeg.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
#include "nvenc_shared.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
#include <libavutil/opt.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
|
||||
#define ST_KEY_PROFILE "H264.Profile"
|
||||
#define ST_KEY_LEVEL "H264.Level"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
using namespace streamfx::encoder::codec::h264;
|
||||
|
||||
void nvenc_h264_handler::adjust_info(ffmpeg_factory* fac, const AVCodec*, std::string&, std::string& name, std::string&)
|
||||
{
|
||||
name = "NVIDIA NVENC H.264/AVC (via FFmpeg)";
|
||||
if (!nvenc::is_available())
|
||||
fac->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
nvenc::get_defaults(settings, codec, context);
|
||||
|
||||
obs_data_set_default_string(settings, ST_KEY_PROFILE, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_LEVEL, "auto");
|
||||
}
|
||||
|
||||
bool nvenc_h264_handler::has_keyframe_support(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_h264_handler::is_hardware_encoder(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_h264_handler::has_threading_support(ffmpeg_factory*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nvenc_h264_handler::has_pixel_format_support(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
if (!context) {
|
||||
this->get_encoder_properties(props, codec);
|
||||
} else {
|
||||
this->get_runtime_properties(props, codec, context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::update(settings, codec, context);
|
||||
|
||||
if (!context->internal) {
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_PROFILE); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "profile", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_LEVEL); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::override_update(ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
nvenc::override_update(instance, settings);
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::log_options(settings, codec, context);
|
||||
|
||||
DLOG_INFO("[%s] H.264/AVC:", codec->name);
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "profile", " Profile", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "level", " Level", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (!context->priv_data) {
|
||||
avcodec_free_context(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
nvenc::get_properties_pre(props, codec, context);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!streamfx::util::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, S_CODEC_H264, D_TRANSLATE(S_CODEC_H264), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_PROFILE, D_TRANSLATE(S_CODEC_H264_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_DEFAULT), "");
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_H264_PROFILE, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_LEVEL, D_TRANSLATE(S_CODEC_H264_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) {
|
||||
if (opt->default_val.i64 == 0) {
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_AUTOMATIC), "auto");
|
||||
} else {
|
||||
obs_property_list_add_string(p, opt->name, opt->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nvenc::get_properties_post(props, codec, context);
|
||||
|
||||
if (context) {
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_h264_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::get_runtime_properties(props, codec, context);
|
||||
}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::nvenc_h264_handler::migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::migrate(settings, version, codec, context);
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
|
||||
// Profile
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_PROFILE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_PROFILE))
|
||||
v = 3;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "baseline"}, {1, "baseline"}, {2, "main"}, {3, "high"}, {4, "high444p"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_PROFILE, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Level
|
||||
obs_data_set_string(settings, ST_KEY_LEVEL, "auto");
|
||||
}
|
||||
}
|
||||
|
||||
bool nvenc_h264_handler::supports_reconfigure(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes)
|
||||
{
|
||||
threads = false;
|
||||
gpu = false;
|
||||
keyframes = false;
|
||||
return true;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#pragma once
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler {
|
||||
class nvenc_h264_handler : public handler {
|
||||
public:
|
||||
virtual ~nvenc_h264_handler(){};
|
||||
|
||||
public /*factory*/:
|
||||
virtual void adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name, std::string& codec_id);
|
||||
|
||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
|
||||
|
||||
virtual std::string_view get_help_url(const AVCodec* codec) override
|
||||
{
|
||||
return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg-NVENC";
|
||||
};
|
||||
|
||||
public /*support tests*/:
|
||||
virtual bool has_keyframe_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool is_hardware_encoder(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_threading_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_pixel_format_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool supports_reconfigure(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes);
|
||||
|
||||
public /*settings*/:
|
||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
|
||||
|
||||
virtual void migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
virtual void override_update(ffmpeg_instance* instance, obs_data_t* settings);
|
||||
|
||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
private:
|
||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
};
|
||||
} // namespace streamfx::encoder::ffmpeg::handler
|
|
@ -1,210 +0,0 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// Copyright (C) 2022 lainon <GermanAizek@yandex.ru>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#include "nvenc_hevc_handler.hpp"
|
||||
#include "common.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "../codecs/hevc.hpp"
|
||||
#include "../encoder-ffmpeg.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
#include "nvenc_shared.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
#include <libavutil/opt.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
|
||||
#define ST_KEY_PROFILE "H265.Profile"
|
||||
#define ST_KEY_TIER "H265.Tier"
|
||||
#define ST_KEY_LEVEL "H265.Level"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
using namespace streamfx::encoder::codec::hevc;
|
||||
|
||||
void nvenc_hevc_handler::adjust_info(ffmpeg_factory* fac, const AVCodec*, std::string&, std::string& name, std::string&)
|
||||
{
|
||||
name = "NVIDIA NVENC H.265/HEVC (via FFmpeg)";
|
||||
if (!nvenc::is_available())
|
||||
fac->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
nvenc::get_defaults(settings, codec, context);
|
||||
|
||||
obs_data_set_default_string(settings, ST_KEY_PROFILE, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_TIER, "");
|
||||
obs_data_set_default_string(settings, ST_KEY_LEVEL, "auto");
|
||||
}
|
||||
|
||||
bool nvenc_hevc_handler::has_keyframe_support(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_hevc_handler::is_hardware_encoder(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_hevc_handler::has_threading_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nvenc_hevc_handler::has_pixel_format_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
if (!context) {
|
||||
this->get_encoder_properties(props, codec);
|
||||
} else {
|
||||
this->get_runtime_properties(props, codec, context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::update(settings, codec, context);
|
||||
|
||||
if (!context->internal) {
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_PROFILE); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "profile", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_TIER); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "tier", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (const char* v = obs_data_get_string(settings, ST_KEY_LEVEL); v && (v[0] != '\0')) {
|
||||
av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::override_update(ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
nvenc::override_update(instance, settings);
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::log_options(settings, codec, context);
|
||||
|
||||
DLOG_INFO("[%s] H.265/HEVC:", codec->name);
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "profile", " Profile", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "level", " Level", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::streamfx::ffmpeg::tools::print_av_option_string2(context, "tier", " Tier", [](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
AVCodecContext* context = avcodec_alloc_context3(codec);
|
||||
if (!context->priv_data) {
|
||||
avcodec_free_context(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
nvenc::get_properties_pre(props, codec, context);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!streamfx::util::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, S_CODEC_HEVC, D_TRANSLATE(S_CODEC_HEVC), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_PROFILE, D_TRANSLATE(S_CODEC_HEVC_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1);
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "profile", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_HEVC_PROFILE, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_TIER, D_TRANSLATE(S_CODEC_HEVC_TIER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), -1);
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "tier", [&p](const AVOption* opt) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", S_CODEC_HEVC_TIER, opt->name);
|
||||
obs_property_list_add_string(p, D_TRANSLATE(buffer), opt->name);
|
||||
});
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_LEVEL, D_TRANSLATE(S_CODEC_HEVC_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) {
|
||||
if (opt->default_val.i64 == 0) {
|
||||
obs_property_list_add_string(p, D_TRANSLATE(S_STATE_AUTOMATIC), "auto");
|
||||
} else {
|
||||
obs_property_list_add_string(p, opt->name, opt->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nvenc::get_properties_post(props, codec, context);
|
||||
|
||||
if (context) {
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
void nvenc_hevc_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::get_runtime_properties(props, codec, context);
|
||||
}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::nvenc_hevc_handler::migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::migrate(settings, version, codec, context);
|
||||
|
||||
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
|
||||
// Profile
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_PROFILE); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_PROFILE))
|
||||
v = 0;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "main"},
|
||||
{1, "main10"},
|
||||
{2, "rext"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_PROFILE, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Tier
|
||||
if (auto v = obs_data_get_int(settings, ST_KEY_TIER); v != -1) {
|
||||
if (!obs_data_has_user_value(settings, ST_KEY_TIER))
|
||||
v = 0;
|
||||
|
||||
std::map<int64_t, std::string> preset{
|
||||
{0, "main"},
|
||||
{1, "high"},
|
||||
};
|
||||
if (auto k = preset.find(v); k != preset.end()) {
|
||||
obs_data_set_string(settings, ST_KEY_TIER, k->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Level
|
||||
obs_data_set_string(settings, ST_KEY_LEVEL, "auto");
|
||||
}
|
||||
}
|
||||
|
||||
bool nvenc_hevc_handler::supports_reconfigure(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes)
|
||||
{
|
||||
threads = false;
|
||||
gpu = false;
|
||||
keyframes = false;
|
||||
return true;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#pragma once
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler {
|
||||
class nvenc_hevc_handler : public handler {
|
||||
public:
|
||||
virtual ~nvenc_hevc_handler(){};
|
||||
|
||||
public /*factory*/:
|
||||
virtual void adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name, std::string& codec_id);
|
||||
|
||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
|
||||
|
||||
virtual std::string_view get_help_url(const AVCodec* codec) override
|
||||
{
|
||||
return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg-NVENC";
|
||||
};
|
||||
|
||||
public /*support tests*/:
|
||||
virtual bool has_keyframe_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool is_hardware_encoder(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_threading_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_pixel_format_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool supports_reconfigure(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes);
|
||||
|
||||
public /*settings*/:
|
||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
|
||||
|
||||
virtual void migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
virtual void override_update(ffmpeg_instance* instance, obs_data_t* settings);
|
||||
|
||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
private:
|
||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
};
|
||||
} // namespace streamfx::encoder::ffmpeg::handler
|
|
@ -1,40 +0,0 @@
|
|||
// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "warning-disable.hpp"
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include "warning-enable.hpp"
|
||||
}
|
||||
|
||||
/* NVENC has multiple compression modes:
|
||||
- CBR: Constant Bitrate (rc=cbr)
|
||||
- VBR: Variable Bitrate (rc=vbr)
|
||||
- CQP: Constant QP (rc=cqp)
|
||||
- CQ: Constant Quality (rc=vbr b=0 maxrate=0 qmin=0 qmax=51 cq=qp), this is basically CRF in X264.
|
||||
*/
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler::nvenc {
|
||||
bool is_available();
|
||||
|
||||
void override_update(ffmpeg_instance* instance, obs_data_t* settings);
|
||||
|
||||
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void get_properties_pre(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context);
|
||||
|
||||
void get_properties_post(obs_properties_t* props, const AVCodec* codec, const AVCodecContext* context);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
} // namespace streamfx::encoder::ffmpeg::handler::nvenc
|
Loading…
Reference in New Issue