encoder, ui/handler: Massive Refactor
This refactor is primarily to make the entire interface more unified and capable of more than before.
This commit is contained in:
+73
-54
@@ -355,10 +355,6 @@ obsffmpeg::encoder_factory::encoder_factory(const AVCodec* codec) : avcodec_ptr(
|
|||||||
sstr << " (" << avcodec_ptr->name << ")";
|
sstr << " (" << avcodec_ptr->name << ")";
|
||||||
}
|
}
|
||||||
info.readable_name = sstr.str();
|
info.readable_name = sstr.str();
|
||||||
|
|
||||||
// Allow UI Handler to replace visible name.
|
|
||||||
if (_handler)
|
|
||||||
_handler->get_name(avcodec_ptr, info.readable_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign Ids.
|
// Assign Ids.
|
||||||
@@ -812,34 +808,6 @@ obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool i
|
|||||||
initialize_sw(settings);
|
initialize_sw(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log Encoder info
|
|
||||||
PLOG_INFO("[%s] Initializing...", _codec->name);
|
|
||||||
if (_hwinst) {
|
|
||||||
PLOG_INFO("[%s] Video Input: %ldx%ld %s %s %s", _codec->name, _context->width, _context->height,
|
|
||||||
ffmpeg::tools::get_pixel_format_name(_context->sw_pix_fmt),
|
|
||||||
ffmpeg::tools::get_color_space_name(_context->colorspace),
|
|
||||||
_swscale.is_source_full_range() ? "Full" : "Partial");
|
|
||||||
PLOG_INFO("[%s] Video Output: %ldx%ld %s %s %s", _codec->name, _context->width, _context->height,
|
|
||||||
ffmpeg::tools::get_pixel_format_name(_context->sw_pix_fmt),
|
|
||||||
ffmpeg::tools::get_color_space_name(_context->colorspace),
|
|
||||||
_swscale.is_target_full_range() ? "Full" : "Partial");
|
|
||||||
} else {
|
|
||||||
PLOG_INFO("[%s] Video Input: %ldx%ld %s %s %s", _codec->name, _swscale.get_source_width(),
|
|
||||||
_swscale.get_source_height(),
|
|
||||||
ffmpeg::tools::get_pixel_format_name(_swscale.get_source_format()),
|
|
||||||
ffmpeg::tools::get_color_space_name(_swscale.get_source_colorspace()),
|
|
||||||
_swscale.is_source_full_range() ? "Full" : "Partial");
|
|
||||||
PLOG_INFO("[%s] Video Output: %ldx%ld %s %s %s", _codec->name, _swscale.get_target_width(),
|
|
||||||
_swscale.get_target_height(),
|
|
||||||
ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()),
|
|
||||||
ffmpeg::tools::get_color_space_name(_swscale.get_target_colorspace()),
|
|
||||||
_swscale.is_target_full_range() ? "Full" : "Partial");
|
|
||||||
PLOG_INFO("[%s] GPU Selected: %d", _codec->name, obs_data_get_int(settings, ST_FFMPEG_GPU));
|
|
||||||
}
|
|
||||||
PLOG_INFO("[%s] Framerate: %ld/%ld (%f FPS)", _codec->name, _context->time_base.den, _context->time_base.num,
|
|
||||||
static_cast<double_t>(_context->time_base.den) / static_cast<double_t>(_context->time_base.num));
|
|
||||||
PLOG_INFO("[%s] Custom Settings: %s", _codec->name, obs_data_get_string(settings, ST_FFMPEG_CUSTOMSETTINGS));
|
|
||||||
|
|
||||||
// Update settings
|
// Update settings
|
||||||
update(settings);
|
update(settings);
|
||||||
|
|
||||||
@@ -895,41 +863,47 @@ void obsffmpeg::encoder::get_properties(obs_properties_t* props, bool hw_encode)
|
|||||||
|
|
||||||
bool obsffmpeg::encoder::update(obs_data_t* settings)
|
bool obsffmpeg::encoder::update(obs_data_t* settings)
|
||||||
{
|
{
|
||||||
// Settings
|
// FFmpeg Options
|
||||||
/// Rate Control
|
|
||||||
_context->strict_std_compliance = static_cast<int>(obs_data_get_int(settings, ST_FFMPEG_STANDARDCOMPLIANCE));
|
|
||||||
_context->debug = 0;
|
_context->debug = 0;
|
||||||
|
_context->strict_std_compliance = static_cast<int>(obs_data_get_int(settings, ST_FFMPEG_STANDARDCOMPLIANCE));
|
||||||
|
|
||||||
/// Threading
|
/// Threading
|
||||||
if (_codec->capabilities & (AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)
|
if (!_hwinst) {
|
||||||
&& !_hwinst) {
|
_context->thread_type = 0;
|
||||||
if (_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
|
if (_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
|
||||||
_context->thread_type |= FF_THREAD_FRAME;
|
_context->thread_type |= FF_THREAD_FRAME;
|
||||||
}
|
}
|
||||||
if (_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
|
if (_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
|
||||||
_context->thread_type |= FF_THREAD_SLICE;
|
_context->thread_type |= FF_THREAD_SLICE;
|
||||||
}
|
}
|
||||||
int64_t threads = obs_data_get_int(settings, ST_FFMPEG_THREADS);
|
if (_context->thread_type != 0) {
|
||||||
if (threads > 0) {
|
int64_t threads = obs_data_get_int(settings, ST_FFMPEG_THREADS);
|
||||||
_context->thread_count = static_cast<int>(threads);
|
if (threads > 0) {
|
||||||
_lag_in_frames = _context->thread_count;
|
_context->thread_count = static_cast<int>(threads);
|
||||||
|
} else {
|
||||||
|
_context->thread_count = std::thread::hardware_concurrency();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_context->thread_count = std::thread::hardware_concurrency();
|
_context->thread_count = 1;
|
||||||
_lag_in_frames = _context->thread_count;
|
|
||||||
}
|
}
|
||||||
|
// Frame Delay (Lag In Frames)
|
||||||
|
_context->delay = _context->thread_count;
|
||||||
} else {
|
} else {
|
||||||
_context->thread_count = 1;
|
_context->delay = 0;
|
||||||
_context->thread_type = 0;
|
|
||||||
_lag_in_frames = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_handler)
|
// Apply GPU Selection
|
||||||
_handler->update(settings, _codec, _context);
|
if (!_hwinst && ffmpeg::tools::can_hardware_encode(_codec)) {
|
||||||
|
av_opt_set_int(_context, "gpu", (int)obs_data_get_int(settings, ST_FFMPEG_GPU), AV_OPT_SEARCH_CHILDREN);
|
||||||
|
}
|
||||||
|
|
||||||
if ((_codec->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0) {
|
// Keyframes
|
||||||
|
if (_handler && _handler->has_keyframe_support(this)) {
|
||||||
// Key-Frame Options
|
// Key-Frame Options
|
||||||
obs_video_info ovi;
|
obs_video_info ovi;
|
||||||
if (!obs_get_video_info(&ovi)) {
|
if (!obs_get_video_info(&ovi)) {
|
||||||
throw std::runtime_error("no video info");
|
throw std::runtime_error(
|
||||||
|
"obs_get_video_info failed, restart OBS Studio to fix it (hopefully).");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t kf_type = obs_data_get_int(settings, S_KEYFRAMES_INTERVALTYPE);
|
int64_t kf_type = obs_data_get_int(settings, S_KEYFRAMES_INTERVALTYPE);
|
||||||
@@ -944,8 +918,9 @@ bool obsffmpeg::encoder::update(obs_data_t* settings)
|
|||||||
_context->keyint_min = _context->gop_size;
|
_context->keyint_min = _context->gop_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_hwinst)
|
// Handler Options
|
||||||
av_opt_set_int(_context, "gpu", (int)obs_data_get_int(settings, ST_FFMPEG_GPU), AV_OPT_SEARCH_CHILDREN);
|
if (_handler)
|
||||||
|
_handler->update(settings, _codec, _context);
|
||||||
|
|
||||||
{ // FFmpeg Custom Options
|
{ // FFmpeg Custom Options
|
||||||
const char* opts = obs_data_get_string(settings, ST_FFMPEG_CUSTOMSETTINGS);
|
const char* opts = obs_data_get_string(settings, ST_FFMPEG_CUSTOMSETTINGS);
|
||||||
@@ -954,12 +929,56 @@ bool obsffmpeg::encoder::update(obs_data_t* settings)
|
|||||||
parse_ffmpeg_commandline(std::string{opts, opts + opts_len});
|
parse_ffmpeg_commandline(std::string{opts, opts + opts_len});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler Overrides
|
||||||
if (_handler)
|
if (_handler)
|
||||||
_handler->override_lag_in_frames(_lag_in_frames, settings, _codec, _context);
|
_handler->override_update(this, settings);
|
||||||
|
|
||||||
// Handler Logging
|
// Handler Logging
|
||||||
if (_handler)
|
if (_handler) {
|
||||||
|
PLOG_INFO("[%s] Initializing...", _codec->name);
|
||||||
|
PLOG_INFO("[%s] FFmpeg:", _codec->name);
|
||||||
|
PLOG_INFO("[%s] Custom Settings: %s", _codec->name,
|
||||||
|
obs_data_get_string(settings, ST_FFMPEG_CUSTOMSETTINGS));
|
||||||
|
PLOG_INFO("[%s] Standard Compliance: %s", _codec->name,
|
||||||
|
ffmpeg::tools::get_std_compliance_name(_context->strict_std_compliance));
|
||||||
|
PLOG_INFO("[%s] Threading: %s (with %i threads)", _codec->name,
|
||||||
|
ffmpeg::tools::get_thread_type_name(_context->thread_type), _context->thread_count);
|
||||||
|
|
||||||
|
PLOG_INFO("[%s] Video:", _codec->name);
|
||||||
|
if (_hwinst) {
|
||||||
|
PLOG_INFO("[%s] Texture: %ldx%ld %s %s %s", _codec->name, _context->width, _context->height,
|
||||||
|
ffmpeg::tools::get_pixel_format_name(_context->sw_pix_fmt),
|
||||||
|
ffmpeg::tools::get_color_space_name(_context->colorspace),
|
||||||
|
av_color_range_name(_context->color_range));
|
||||||
|
} else {
|
||||||
|
PLOG_INFO("[%s] Input: %ldx%ld %s %s %s", _codec->name, _swscale.get_source_width(),
|
||||||
|
_swscale.get_source_height(),
|
||||||
|
ffmpeg::tools::get_pixel_format_name(_swscale.get_source_format()),
|
||||||
|
ffmpeg::tools::get_color_space_name(_swscale.get_source_colorspace()),
|
||||||
|
_swscale.is_source_full_range() ? "Full" : "Partial");
|
||||||
|
PLOG_INFO("[%s] Output: %ldx%ld %s %s %s", _codec->name, _swscale.get_target_width(),
|
||||||
|
_swscale.get_target_height(),
|
||||||
|
ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()),
|
||||||
|
ffmpeg::tools::get_color_space_name(_swscale.get_target_colorspace()),
|
||||||
|
_swscale.is_target_full_range() ? "Full" : "Partial");
|
||||||
|
if (!_hwinst)
|
||||||
|
PLOG_INFO("[%s] On GPU Index: %lli", _codec->name,
|
||||||
|
obs_data_get_int(settings, ST_FFMPEG_GPU));
|
||||||
|
}
|
||||||
|
PLOG_INFO("[%s] Framerate: %ld/%ld (%f FPS)", _codec->name, _context->time_base.den,
|
||||||
|
_context->time_base.num,
|
||||||
|
static_cast<double_t>(_context->time_base.den)
|
||||||
|
/ static_cast<double_t>(_context->time_base.num));
|
||||||
|
|
||||||
|
PLOG_INFO("[%s] Keyframes: ", _codec->name);
|
||||||
|
if (_context->keyint_min != _context->gop_size) {
|
||||||
|
PLOG_INFO("[%s] Minimum: %i frames", _context->keyint_min);
|
||||||
|
PLOG_INFO("[%s] Maximum: %i frames", _context->gop_size);
|
||||||
|
} else {
|
||||||
|
PLOG_INFO("[%s] Distance: %i frames", _context->gop_size);
|
||||||
|
}
|
||||||
_handler->log_options(settings, _codec, _context);
|
_handler->log_options(settings, _codec, _context);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-18
@@ -20,34 +20,27 @@
|
|||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include "handler.hpp"
|
#include "handler.hpp"
|
||||||
|
#include "encoder.hpp"
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::get_name(const AVCodec*, std::string&) {}
|
void obsffmpeg::ui::handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info*,
|
||||||
|
obsffmpeg::encoder_info*)
|
||||||
void obsffmpeg::ui::handler::override_info(obs_encoder_info*, obs_encoder_info*) {}
|
{}
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::override_lag_in_frames(size_t&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
|
void obsffmpeg::ui::handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::get_properties(obs_properties_t*, const AVCodec*, AVCodecContext*, bool) {}
|
bool obsffmpeg::ui::handler::has_keyframe_support(obsffmpeg::encoder* instance)
|
||||||
|
|
||||||
obsffmpeg::hwapi::device obsffmpeg::ui::handler::find_hw_device(std::shared_ptr<obsffmpeg::hwapi::base>, const AVCodec*,
|
|
||||||
AVCodecContext*)
|
|
||||||
{
|
{
|
||||||
return obsffmpeg::hwapi::device();
|
return (instance->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obsffmpeg::ui::handler::get_properties(obs_properties_t*, const AVCodec*, AVCodecContext*, bool) {}
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::update(obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
void obsffmpeg::ui::handler::update(obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
||||||
|
|
||||||
|
void obsffmpeg::ui::handler::override_update(obsffmpeg::encoder*, obs_data_t*) {}
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::log_options(obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
void obsffmpeg::ui::handler::log_options(obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::import_from_ffmpeg(const std::string, obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
|
||||||
|
|
||||||
std::string obsffmpeg::ui::handler::export_for_ffmpeg(obs_data_t*, const AVCodec*, AVCodecContext*)
|
|
||||||
{
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
void obsffmpeg::ui::handler::process_avpacket(AVPacket&, const AVCodec*, AVCodecContext*) {}
|
void obsffmpeg::ui::handler::process_avpacket(AVPacket&, const AVCodec*, AVCodecContext*) {}
|
||||||
|
|||||||
+13
-19
@@ -22,7 +22,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "encoder.hpp"
|
|
||||||
#include "hwapi/base.hpp"
|
#include "hwapi/base.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -38,41 +37,36 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace obsffmpeg {
|
namespace obsffmpeg {
|
||||||
|
struct encoder_info;
|
||||||
|
class encoder_factory;
|
||||||
|
class encoder;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class handler {
|
class handler {
|
||||||
public /*factory*/:
|
public /*factory*/:
|
||||||
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
|
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
|
||||||
obsffmpeg::encoder_info* main,
|
obsffmpeg::encoder_info* main,
|
||||||
obsffmpeg::encoder_info* fallback) = 0;
|
obsffmpeg::encoder_info* fallback);
|
||||||
|
|
||||||
public /*instance*/:
|
|
||||||
|
|
||||||
virtual void get_name(const AVCodec* codec, std::string& name);
|
|
||||||
|
|
||||||
virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
|
|
||||||
const AVCodec* codec, AVCodecContext* context);
|
|
||||||
|
|
||||||
virtual void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
|
||||||
AVCodecContext* context);
|
|
||||||
|
|
||||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
||||||
bool hw_encode);
|
bool hw_encode);
|
||||||
|
|
||||||
|
public /*settings*/:
|
||||||
|
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
|
||||||
|
|
||||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
||||||
AVCodecContext* context, bool hw_encode);
|
AVCodecContext* context, bool hw_encode);
|
||||||
|
|
||||||
virtual obsffmpeg::hwapi::device find_hw_device(std::shared_ptr<obsffmpeg::hwapi::base> api,
|
|
||||||
const AVCodec* codec, AVCodecContext* context);
|
|
||||||
|
|
||||||
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
|
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
|
||||||
|
|
||||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
virtual void import_from_ffmpeg(const std::string ffmpeg, obs_data_t* settings,
|
public /*instance*/:
|
||||||
const AVCodec* codec, AVCodecContext* context);
|
|
||||||
|
|
||||||
virtual std::string export_for_ffmpeg(obs_data_t* settings, const AVCodec* codec,
|
virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
|
||||||
AVCodecContext* context);
|
const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
virtual void process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context);
|
virtual void process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "nvenc_h264_handler.hpp"
|
#include "nvenc_h264_handler.hpp"
|
||||||
#include "codecs/h264.hpp"
|
#include "codecs/h264.hpp"
|
||||||
|
#include "encoder.hpp"
|
||||||
#include "nvenc_shared.hpp"
|
#include "nvenc_shared.hpp"
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
#include "strings.hpp"
|
#include "strings.hpp"
|
||||||
@@ -80,15 +81,11 @@ INITIALIZER(nvenc_h264_handler_init)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_h264_handler::get_name(const AVCodec*, std::string& name)
|
void obsffmpeg::ui::nvenc_h264_handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info* main,
|
||||||
|
obsffmpeg::encoder_info* fallback)
|
||||||
{
|
{
|
||||||
name = "H.264/AVC Encoder (NVidia NVENC)";
|
main->readable_name = "H.264/AVC Encoder (NVidia NVENC) (Hardware)";
|
||||||
}
|
fallback->readable_name = "H.264/AVC Encoder (NVidia NVENC) (Software)";
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_h264_handler::override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
|
||||||
AVCodecContext* context)
|
|
||||||
{
|
|
||||||
nvenc::override_lag_in_frames(lag, settings, codec, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
|
void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
|
||||||
@@ -100,6 +97,11 @@ void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const
|
|||||||
obs_data_set_default_int(settings, P_H264_LEVEL, static_cast<int64_t>(codecs::h264::level::UNKNOWN));
|
obs_data_set_default_int(settings, P_H264_LEVEL, static_cast<int64_t>(codecs::h264::level::UNKNOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool obsffmpeg::ui::nvenc_h264_handler::has_keyframe_support(obsffmpeg::encoder*)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_h264_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
|
void obsffmpeg::ui::nvenc_h264_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
|
||||||
AVCodecContext* context, bool)
|
AVCodecContext* context, bool)
|
||||||
{
|
{
|
||||||
@@ -132,6 +134,11 @@ void obsffmpeg::ui::nvenc_h264_handler::update(obs_data_t* settings, const AVCod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obsffmpeg::ui::nvenc_h264_handler::override_update(obsffmpeg::encoder* instance, obs_data_t* settings)
|
||||||
|
{
|
||||||
|
nvenc::override_update(instance, settings);
|
||||||
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
void obsffmpeg::ui::nvenc_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||||
{
|
{
|
||||||
nvenc::log_options(settings, codec, context);
|
nvenc::log_options(settings, codec, context);
|
||||||
|
|||||||
@@ -33,23 +33,28 @@ extern "C" {
|
|||||||
namespace obsffmpeg {
|
namespace obsffmpeg {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class nvenc_h264_handler : public handler {
|
class nvenc_h264_handler : public handler {
|
||||||
public:
|
public /*factory*/:
|
||||||
virtual void get_name(const AVCodec* codec, std::string& name) override;
|
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
|
||||||
|
obsffmpeg::encoder_info* main,
|
||||||
virtual void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
obsffmpeg::encoder_info* fallback);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
|
||||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
||||||
bool hw_encode) override;
|
bool hw_encode);
|
||||||
|
|
||||||
|
public /*settings*/:
|
||||||
|
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
|
||||||
|
|
||||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
||||||
AVCodecContext* context, bool hw_encode) override;
|
AVCodecContext* context, bool hw_encode);
|
||||||
|
|
||||||
virtual void update(obs_data_t* settings, const AVCodec* codec,
|
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
|
||||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec,
|
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
|
public /*instance*/:
|
||||||
|
//virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "nvenc_hevc_handler.hpp"
|
#include "nvenc_hevc_handler.hpp"
|
||||||
#include "codecs/hevc.hpp"
|
#include "codecs/hevc.hpp"
|
||||||
|
#include "encoder.hpp"
|
||||||
#include "nvenc_shared.hpp"
|
#include "nvenc_shared.hpp"
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
#include "strings.hpp"
|
#include "strings.hpp"
|
||||||
@@ -82,15 +83,11 @@ INITIALIZER(nvenc_hevc_handler_init)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_hevc_handler::get_name(const AVCodec*, std::string& name)
|
void obsffmpeg::ui::nvenc_hevc_handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info* main,
|
||||||
|
obsffmpeg::encoder_info* fallback)
|
||||||
{
|
{
|
||||||
name = "H.265/HEVC Encoder (NVidia NVENC)";
|
main->readable_name = "H.265/HEVC Encoder (Nvidia NVENC) (Hardware)";
|
||||||
}
|
fallback->readable_name = "H.265/HEVC Encoder (Nvidia NVENC) (Software)";
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_hevc_handler::override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
|
||||||
AVCodecContext* context)
|
|
||||||
{
|
|
||||||
nvenc::override_lag_in_frames(lag, settings, codec, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
|
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
|
||||||
@@ -103,6 +100,11 @@ void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const
|
|||||||
obs_data_set_default_int(settings, P_HEVC_LEVEL, static_cast<int64_t>(codecs::hevc::level::UNKNOWN));
|
obs_data_set_default_int(settings, P_HEVC_LEVEL, static_cast<int64_t>(codecs::hevc::level::UNKNOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool obsffmpeg::ui::nvenc_hevc_handler::has_keyframe_support(obsffmpeg::encoder*)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_hevc_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
|
void obsffmpeg::ui::nvenc_hevc_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
|
||||||
AVCodecContext* context, bool)
|
AVCodecContext* context, bool)
|
||||||
{
|
{
|
||||||
@@ -139,6 +141,11 @@ void obsffmpeg::ui::nvenc_hevc_handler::update(obs_data_t* settings, const AVCod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obsffmpeg::ui::nvenc_hevc_handler::override_update(obsffmpeg::encoder* instance, obs_data_t* settings)
|
||||||
|
{
|
||||||
|
nvenc::override_update(instance, settings);
|
||||||
|
}
|
||||||
|
|
||||||
void obsffmpeg::ui::nvenc_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
void obsffmpeg::ui::nvenc_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||||
{
|
{
|
||||||
nvenc::log_options(settings, codec, context);
|
nvenc::log_options(settings, codec, context);
|
||||||
|
|||||||
@@ -33,23 +33,28 @@ extern "C" {
|
|||||||
namespace obsffmpeg {
|
namespace obsffmpeg {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class nvenc_hevc_handler : public handler {
|
class nvenc_hevc_handler : public handler {
|
||||||
public:
|
public /*factory*/:
|
||||||
virtual void get_name(const AVCodec* codec, std::string& name) override;
|
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
|
||||||
|
obsffmpeg::encoder_info* main,
|
||||||
virtual void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
obsffmpeg::encoder_info* fallback);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
|
||||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
|
||||||
bool hw_encode) override;
|
bool hw_encode);
|
||||||
|
|
||||||
|
public /*settings*/:
|
||||||
|
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
|
||||||
|
|
||||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
|
||||||
AVCodecContext* context, bool hw_encode) override;
|
AVCodecContext* context, bool hw_encode);
|
||||||
|
|
||||||
virtual void update(obs_data_t* settings, const AVCodec* codec,
|
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
|
||||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec,
|
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
|
||||||
AVCodecContext* context) override;
|
|
||||||
|
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
|
public /*instance*/:
|
||||||
|
//virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "nvenc_shared.hpp"
|
#include "nvenc_shared.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "codecs/hevc.hpp"
|
#include "codecs/hevc.hpp"
|
||||||
|
#include "encoder.hpp"
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
#include "strings.hpp"
|
#include "strings.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
@@ -132,17 +133,34 @@ std::map<b_ref_mode, std::string> obsffmpeg::nvenc::b_ref_mode_to_opt{
|
|||||||
{b_ref_mode::MIDDLE, "middle"},
|
{b_ref_mode::MIDDLE, "middle"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void obsffmpeg::nvenc::override_lag_in_frames(size_t& lag, obs_data_t*, const AVCodec*, AVCodecContext* context)
|
void obsffmpeg::nvenc::override_update(obsffmpeg::encoder* instance, obs_data_t*)
|
||||||
{
|
{
|
||||||
// With NVENC, the number of frames lagged before we get our first
|
AVCodecContext* context = const_cast<AVCodecContext*>(instance->get_avcodeccontext());
|
||||||
// packet is determined by the number of b-frames. Threads, lookahead
|
|
||||||
// frames and various other settings are ignored.
|
|
||||||
// The minimum number of lagged frames is 1.
|
|
||||||
|
|
||||||
int64_t rcla = 0;
|
int64_t rclookahead = 0;
|
||||||
av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rcla);
|
int64_t surfaces = 0;
|
||||||
|
int64_t async_depth = 0;
|
||||||
|
|
||||||
lag = static_cast<size_t>(std::max(1ll + static_cast<int64_t>(context->max_b_frames), rcla));
|
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(4ll, (context->max_b_frames + 1ll) * 4ll);
|
||||||
|
if (rclookahead > 0) {
|
||||||
|
surfaces = std::max(1ll, std::max(surfaces, rclookahead + (context->max_b_frames + 5ll)));
|
||||||
|
} else if (context->max_b_frames > 0) {
|
||||||
|
surfaces = std::max(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 = static_cast<int>(std::min(std::max(async_depth, 3ll), surfaces - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
|
void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace obsffmpeg {
|
namespace obsffmpeg {
|
||||||
|
class encoder;
|
||||||
|
|
||||||
namespace nvenc {
|
namespace nvenc {
|
||||||
enum class preset : int64_t {
|
enum class preset : int64_t {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
@@ -75,8 +77,7 @@ namespace obsffmpeg {
|
|||||||
|
|
||||||
extern std::map<b_ref_mode, std::string> b_ref_mode_to_opt;
|
extern std::map<b_ref_mode, std::string> b_ref_mode_to_opt;
|
||||||
|
|
||||||
void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
|
void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
|
||||||
AVCodecContext* context);
|
|
||||||
|
|
||||||
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user