From 19689d1a1159a80e65b78c2183b49949cb7c7cc0 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Fri, 3 Dec 2021 07:13:08 +0100 Subject: [PATCH] encoders/ffmpeg: Add support for re-configuration of encoders --- source/encoders/encoder-ffmpeg.cpp | 143 ++++++++++++++++----------- source/encoders/handlers/handler.cpp | 5 + source/encoders/handlers/handler.hpp | 2 + 3 files changed, 90 insertions(+), 60 deletions(-) diff --git a/source/encoders/encoder-ffmpeg.cpp b/source/encoders/encoder-ffmpeg.cpp index 185050af..a913cb0a 100644 --- a/source/encoders/encoder-ffmpeg.cpp +++ b/source/encoders/encoder-ffmpeg.cpp @@ -191,78 +191,98 @@ void ffmpeg_instance::migrate(obs_data_t* settings, uint64_t version) bool ffmpeg_instance::update(obs_data_t* settings) { - // FFmpeg Options - _context->debug = 0; - _context->strict_std_compliance = FF_COMPLIANCE_NORMAL; + bool support_reconfig = false; + bool support_reconfig_threads = false; + bool support_reconfig_gpu = false; + bool support_reconfig_keyframes = false; + if (_handler) { + support_reconfig = _handler->supports_reconfigure(_factory, support_reconfig_threads, support_reconfig_gpu, + support_reconfig_keyframes); + } - /// Threading - if (!_hwinst) { - _context->thread_type = 0; - if (_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { - _context->thread_type |= FF_THREAD_FRAME; - } - if (_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { - _context->thread_type |= FF_THREAD_SLICE; - } - if (_context->thread_type != 0) { - int64_t threads = obs_data_get_int(settings, ST_I18N_FFMPEG_THREADS); - if (threads > 0) { - _context->thread_count = static_cast(threads); - } else { - _context->thread_count = static_cast(std::thread::hardware_concurrency()); + if (!_context->internal) { + // FFmpeg Options + _context->debug = 0; + _context->strict_std_compliance = FF_COMPLIANCE_NORMAL; + } + + if (!_context->internal || (support_reconfig && support_reconfig_threads)) { + /// Threading + if (!_hwinst) { + _context->thread_type = 0; + if (_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { + _context->thread_type |= FF_THREAD_FRAME; } + if (_codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { + _context->thread_type |= FF_THREAD_SLICE; + } + if (_context->thread_type != 0) { + int64_t threads = obs_data_get_int(settings, ST_I18N_FFMPEG_THREADS); + if (threads > 0) { + _context->thread_count = static_cast(threads); + } else { + _context->thread_count = static_cast(std::thread::hardware_concurrency()); + } + } else { + _context->thread_count = 1; + } + + // Frame Delay (Lag In Frames) + _context->delay = _context->thread_count; } else { - _context->thread_count = 1; + _context->delay = 0; } - // Frame Delay (Lag In Frames) - _context->delay = _context->thread_count; - } else { - _context->delay = 0; } - // Apply GPU Selection - if (!_hwinst && ::streamfx::ffmpeg::tools::can_hardware_encode(_codec)) { - av_opt_set_int(_context, "gpu", (int)obs_data_get_int(settings, ST_KEY_FFMPEG_GPU), AV_OPT_SEARCH_CHILDREN); + if (!_context->internal || (support_reconfig && support_reconfig_gpu)) { + // Apply GPU Selection + if (!_hwinst && ::streamfx::ffmpeg::tools::can_hardware_encode(_codec)) { + av_opt_set_int(_context, "gpu", (int)obs_data_get_int(settings, ST_KEY_FFMPEG_GPU), AV_OPT_SEARCH_CHILDREN); + } } - // Keyframes - if (_handler && _handler->has_keyframe_support(_factory)) { - // Key-Frame Options - obs_video_info ovi; - if (!obs_get_video_info(&ovi)) { - throw std::runtime_error("obs_get_video_info failed, restart OBS Studio to fix it (hopefully)."); + if (!_context->internal || (support_reconfig && support_reconfig_keyframes)) { + // Keyframes + if (_handler && _handler->has_keyframe_support(_factory)) { + // Key-Frame Options + obs_video_info ovi; + if (!obs_get_video_info(&ovi)) { + 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, ST_KEY_KEYFRAMES_INTERVALTYPE); + bool is_seconds = (kf_type == 0); + + if (is_seconds) { + _context->gop_size = static_cast(obs_data_get_double(settings, ST_KEY_KEYFRAMES_INTERVAL_SECONDS) + * (ovi.fps_num / ovi.fps_den)); + } else { + _context->gop_size = static_cast(obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVAL_FRAMES)); + } + _context->keyint_min = _context->gop_size; + } + } + + if (!_context->internal || support_reconfig) { + // Handler Options + if (_handler) + _handler->update(settings, _codec, _context); + + { // FFmpeg Custom Options + const char* opts = obs_data_get_string(settings, ST_KEY_FFMPEG_CUSTOMSETTINGS); + std::size_t opts_len = strnlen(opts, 65535); + + parse_ffmpeg_commandline(std::string{opts, opts + opts_len}); } - int64_t kf_type = obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVALTYPE); - bool is_seconds = (kf_type == 0); - - if (is_seconds) { - _context->gop_size = static_cast(obs_data_get_double(settings, ST_KEY_KEYFRAMES_INTERVAL_SECONDS) - * (ovi.fps_num / ovi.fps_den)); - } else { - _context->gop_size = static_cast(obs_data_get_int(settings, ST_KEY_KEYFRAMES_INTERVAL_FRAMES)); - } - _context->keyint_min = _context->gop_size; + // Handler Overrides + if (_handler) + _handler->override_update(this, settings); } - // Handler Options - if (_handler) - _handler->update(settings, _codec, _context); - - { // FFmpeg Custom Options - const char* opts = obs_data_get_string(settings, ST_KEY_FFMPEG_CUSTOMSETTINGS); - std::size_t opts_len = strnlen(opts, 65535); - - parse_ffmpeg_commandline(std::string{opts, opts + opts_len}); - } - - // Handler Overrides - if (_handler) - _handler->override_update(this, settings); - // Handler Logging - if (_handler) { - DLOG_INFO("[%s] Initializing...", _codec->name); + if (!_context->internal || support_reconfig) { + DLOG_INFO("[%s] Configuration:", _codec->name); DLOG_INFO("[%s] FFmpeg:", _codec->name); DLOG_INFO("[%s] Custom Settings: %s", _codec->name, obs_data_get_string(settings, ST_KEY_FFMPEG_CUSTOMSETTINGS)); @@ -302,7 +322,10 @@ bool ffmpeg_instance::update(obs_data_t* settings) } else { DLOG_INFO("[%s] Distance: %i frames", _codec->name, _context->gop_size); } - _handler->log_options(settings, _codec, _context); + + if (_handler) { + _handler->log_options(settings, _codec, _context); + } } return true; diff --git a/source/encoders/handlers/handler.cpp b/source/encoders/handlers/handler.cpp index 4eae21b7..039b6ba5 100644 --- a/source/encoders/handlers/handler.cpp +++ b/source/encoders/handlers/handler.cpp @@ -43,3 +43,8 @@ bool handler::handler::has_pixel_format_support(ffmpeg_factory* instance) { return (instance->get_avcodec()->pix_fmts != nullptr); } + +bool handler::handler::supports_reconfigure(ffmpeg_factory* instance, bool& threads, bool& gpu, bool& keyframes) +{ + return false; +} diff --git a/source/encoders/handlers/handler.hpp b/source/encoders/handlers/handler.hpp index 402a1ec3..b3bc772f 100644 --- a/source/encoders/handlers/handler.hpp +++ b/source/encoders/handlers/handler.hpp @@ -61,6 +61,8 @@ namespace streamfx::encoder::ffmpeg { 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){};