diff --git a/source/encoders/encoder-ffmpeg.cpp b/source/encoders/encoder-ffmpeg.cpp index 134c356a..ece3ec32 100644 --- a/source/encoders/encoder-ffmpeg.cpp +++ b/source/encoders/encoder-ffmpeg.cpp @@ -10,7 +10,6 @@ #include "strings.hpp" #include "codecs/hevc.hpp" #include "ffmpeg/tools.hpp" -#include "handlers/debug_handler.hpp" #include "obs/gs/gs-helper.hpp" #include "plugin.hpp" @@ -32,24 +31,6 @@ extern "C" { #include "warning-enable.hpp" } -#ifdef ENABLE_ENCODER_FFMPEG_AMF -#include "handlers/amf_h264_handler.hpp" -#include "handlers/amf_hevc_handler.hpp" -#endif - -#ifdef ENABLE_ENCODER_FFMPEG_NVENC -#include "handlers/nvenc_h264_handler.hpp" -#include "handlers/nvenc_hevc_handler.hpp" -#endif - -#ifdef ENABLE_ENCODER_FFMPEG_PRORES -#include "handlers/prores_aw_handler.hpp" -#endif - -#ifdef ENABLE_ENCODER_FFMPEG_DNXHR -#include "handlers/dnxhd_handler.hpp" -#endif - #ifdef WIN32 #include "ffmpeg/hwapi/d3d11.hpp" #endif @@ -176,7 +157,7 @@ ffmpeg_instance::~ffmpeg_instance() void ffmpeg_instance::get_properties(obs_properties_t* props) { if (_handler) - _handler->get_properties(props, _codec, _context, _handler->is_hardware_encoder(_factory)); + _handler->properties(this->_factory, this, props); obs_property_set_enabled(obs_properties_get(props, ST_KEY_KEYFRAMES_INTERVALTYPE), false); obs_property_set_enabled(obs_properties_get(props, ST_KEY_KEYFRAMES_INTERVAL_SECONDS), false); @@ -189,7 +170,7 @@ void ffmpeg_instance::get_properties(obs_properties_t* props) void ffmpeg_instance::migrate(obs_data_t* settings, uint64_t version) { if (_handler) - _handler->migrate(settings, version, _codec, _context); + _handler->migrate(this->_factory, this, settings, version); } bool ffmpeg_instance::update(obs_data_t* settings) @@ -199,7 +180,7 @@ bool ffmpeg_instance::update(obs_data_t* settings) 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); + support_reconfig = _handler->is_reconfigurable(_factory, support_reconfig_threads, support_reconfig_gpu, support_reconfig_keyframes); } if (!_context->internal) { @@ -245,7 +226,7 @@ bool ffmpeg_instance::update(obs_data_t* settings) if (!_context->internal || (support_reconfig && support_reconfig_keyframes)) { // Keyframes - if (_handler && _handler->has_keyframe_support(_factory)) { + if (_handler && _handler->has_keyframes(_factory)) { // Key-Frame Options obs_video_info ovi; if (!obs_get_video_info(&ovi)) { @@ -268,7 +249,7 @@ bool ffmpeg_instance::update(obs_data_t* settings) if (!_context->internal || support_reconfig) { // Handler Options if (_handler) - _handler->update(settings, _codec, _context); + _handler->update(this->_factory, this, settings); { // FFmpeg Custom Options const char* opts = obs_data_get_string(settings, ST_KEY_FFMPEG_CUSTOMSETTINGS); @@ -279,7 +260,7 @@ bool ffmpeg_instance::update(obs_data_t* settings) // Handler Overrides if (_handler) - _handler->override_update(this, settings); + _handler->override_update(this->_factory, this, settings); } // Handler Logging @@ -310,7 +291,7 @@ bool ffmpeg_instance::update(obs_data_t* settings) } if (_handler) { - _handler->log_options(settings, _codec, _context); + _handler->log(this->_factory, this, settings); } } @@ -438,7 +419,7 @@ void ffmpeg_instance::initialize_sw(obs_data_t* settings) } if (_handler) // Allow Handler to override the automatic color format for sanity reasons. - _handler->override_colorformat(pix_fmt_target, settings, _codec, _context); + _handler->override_colorformat(this->_factory, this, settings, pix_fmt_target); } // Setup from OBS information. @@ -634,8 +615,9 @@ int ffmpeg_instance::receive_packet(bool* received_packet, struct encoder_packet } // Allow Handler Post-Processing - if (_handler) - _handler->process_avpacket(_packet, _codec, _context); + //FIXME! Is this still necessary? + //if (_handler) + // _handler->process_avpacket(_packet, _codec, _context); // Build packet for use in OBS. packet->type = OBS_ENCODER_VIDEO; @@ -960,10 +942,10 @@ ffmpeg_factory::ffmpeg_factory(ffmpeg_manager* manager, const AVCodec* codec) : // Find any available handlers for this codec. if (_handler = manager->get_handler(_avcodec->name); _handler) { // Override any found info with the one specified by the handler. - _handler->adjust_info(this, _avcodec, _id, _name, _codec); + _handler->adjust_info(this, _id, _name, _codec); // Add texture capability for hardware encoders. - if (_handler->is_hardware_encoder(this)) { + if (_handler->is_hardware(this)) { _info.caps |= OBS_ENCODER_CAP_PASS_TEXTURE; } } else { @@ -1007,9 +989,9 @@ const char* ffmpeg_factory::get_name() void ffmpeg_factory::get_defaults2(obs_data_t* settings) { if (_handler) { - _handler->get_defaults(settings, _avcodec, nullptr, _handler->is_hardware_encoder(this)); + _handler->defaults(this, settings); - if (_handler->has_keyframe_support(this)) { + if (_handler->has_keyframes(this)) { obs_data_set_default_int(settings, ST_KEY_KEYFRAMES_INTERVALTYPE, 0); obs_data_set_default_double(settings, ST_KEY_KEYFRAMES_INTERVAL_SECONDS, 2.0); obs_data_set_default_int(settings, ST_KEY_KEYFRAMES_INTERVAL_FRAMES, 300); @@ -1027,7 +1009,7 @@ void ffmpeg_factory::get_defaults2(obs_data_t* settings) void ffmpeg_factory::migrate(obs_data_t* data, uint64_t version) { if (_handler) - _handler->migrate(data, version, _avcodec, nullptr); + _handler->migrate(this, nullptr, data, version); } static bool modified_keyframes(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept @@ -1061,9 +1043,9 @@ obs_properties_t* ffmpeg_factory::get_properties2(instance_t* data) } if (_handler) - _handler->get_properties(props, _avcodec, nullptr, _handler->is_hardware_encoder(this)); + _handler->properties(this, data, props); - if (_handler && _handler->has_keyframe_support(this)) { + if (_handler && _handler->has_keyframes(this)) { // Key-Frame Options obs_properties_t* grp = props; if (!streamfx::util::are_property_groups_broken()) { @@ -1099,11 +1081,11 @@ obs_properties_t* ffmpeg_factory::get_properties2(instance_t* data) auto p = obs_properties_add_text(grp, ST_KEY_FFMPEG_CUSTOMSETTINGS, D_TRANSLATE(ST_I18N_FFMPEG_CUSTOMSETTINGS), obs_text_type::OBS_TEXT_DEFAULT); } - if (_handler && _handler->is_hardware_encoder(this)) { + if (_handler && _handler->is_hardware(this)) { auto p = obs_properties_add_int(grp, ST_KEY_FFMPEG_GPU, D_TRANSLATE(ST_I18N_FFMPEG_GPU), -1, std::numeric_limits::max(), 1); } - if (_handler && _handler->has_threading_support(this)) { + if (_handler && _handler->has_threading(this)) { auto p = obs_properties_add_int_slider(grp, ST_KEY_FFMPEG_THREADS, D_TRANSLATE(ST_I18N_FFMPEG_THREADS), 0, static_cast(std::thread::hardware_concurrency()) * 2, 1); } @@ -1132,7 +1114,7 @@ obs_properties_t* ffmpeg_factory::get_properties2(instance_t* data) bool ffmpeg_factory::on_manual_open(obs_properties_t* props, obs_property_t* property, void* data) { ffmpeg_factory* ptr = static_cast(data); - streamfx::open_url(ptr->_handler->get_help_url(ptr->_avcodec)); + streamfx::open_url(ptr->_handler->help(ptr)); return false; } #endif @@ -1147,25 +1129,8 @@ obs_encoder_info* streamfx::encoder::ffmpeg::ffmpeg_factory::get_info() return &_info; } -ffmpeg_manager::ffmpeg_manager() : _factories(), _handlers(), _debug_handler() +ffmpeg_manager::ffmpeg_manager() : _factories() { - // Handlers - _debug_handler = ::std::make_shared(); -#ifdef ENABLE_ENCODER_FFMPEG_AMF - register_handler("h264_amf", ::std::make_shared()); - register_handler("hevc_amf", ::std::make_shared()); -#endif -#ifdef ENABLE_ENCODER_FFMPEG_NVENC - register_handler("h264_nvenc", ::std::make_shared()); - register_handler("hevc_nvenc", ::std::make_shared()); -#endif -#ifdef ENABLE_ENCODER_FFMPEG_PRORES - register_handler("prores_aw", ::std::make_shared()); -#endif -#ifdef ENABLE_ENCODER_FFMPEG_DNXHR - register_handler("dnxhd", ::std::make_shared()); -#endif - // Encoders void* iterator = nullptr; for (const AVCodec* codec = av_codec_iterate(&iterator); codec != nullptr; codec = av_codec_iterate(&iterator)) { @@ -1188,28 +1153,6 @@ ffmpeg_manager::~ffmpeg_manager() _factories.clear(); } -void ffmpeg_manager::register_handler(std::string codec, std::shared_ptr handler) -{ - _handlers.emplace(codec, handler); -} - -std::shared_ptr ffmpeg_manager::get_handler(std::string codec) -{ - auto fnd = _handlers.find(codec); - if (fnd != _handlers.end()) - return fnd->second; -#ifdef _DEBUG - return _debug_handler; -#else - return nullptr; -#endif -} - -bool ffmpeg_manager::has_handler(std::string_view codec) -{ - return (_handlers.find(codec.data()) != _handlers.end()); -} - std::shared_ptr ffmpeg_manager::instance() { static std::weak_ptr winst; @@ -1224,6 +1167,30 @@ std::shared_ptr ffmpeg_manager::instance() return instance; } +streamfx::encoder::ffmpeg::handler* ffmpeg_manager::find_handler(std::string_view codec) +{ + auto handlers = streamfx::encoder::ffmpeg::handler::handlers(); + if (auto kv = handlers.find(std::string{codec}); kv != handlers.end()) { + return kv->second; + } +#ifdef _DEBUG + if (auto kv = handlers.find(""); kv != handlers.end()) { + return kv->second; + } +#endif + return nullptr; +} + +streamfx::encoder::ffmpeg::handler* ffmpeg_manager::get_handler(std::string_view codec) +{ + return find_handler(codec); +} + +bool ffmpeg_manager::has_handler(std::string_view codec) +{ + return find_handler(codec) != nullptr; +} + static std::shared_ptr loader_instance; static auto loader = streamfx::loader( diff --git a/source/encoders/encoder-ffmpeg.hpp b/source/encoders/encoder-ffmpeg.hpp index f5e39ac3..9a980b2f 100644 --- a/source/encoders/encoder-ffmpeg.hpp +++ b/source/encoders/encoder-ffmpeg.hpp @@ -5,10 +5,10 @@ #pragma once #include "common.hpp" +#include "encoders/ffmpeg/handler.hpp" #include "ffmpeg/avframe-queue.hpp" #include "ffmpeg/hwapi/base.hpp" #include "ffmpeg/swscale.hpp" -#include "handlers/handler.hpp" #include "obs/obs-encoder-factory.hpp" #include "warning-disable.hpp" @@ -17,16 +17,15 @@ #include #include #include +#include +#include #include #include -#include "warning-enable.hpp" - extern "C" { -#include "warning-disable.hpp" #include #include -#include "warning-enable.hpp" } +#include "warning-enable.hpp" namespace streamfx::encoder::ffmpeg { class ffmpeg_instance; @@ -38,7 +37,7 @@ namespace streamfx::encoder::ffmpeg { const AVCodec* _codec; AVCodecContext* _context; - std::shared_ptr _handler; + streamfx::encoder::ffmpeg::handler* _handler; ::streamfx::ffmpeg::swscale _scaler; std::shared_ptr _packet; @@ -116,7 +115,7 @@ namespace streamfx::encoder::ffmpeg { const AVCodec* _avcodec; - std::shared_ptr _handler; + streamfx::encoder::ffmpeg::handler* _handler; public: ffmpeg_factory(ffmpeg_manager* manager, const AVCodec* codec); @@ -142,16 +141,14 @@ namespace streamfx::encoder::ffmpeg { class ffmpeg_manager { std::map> _factories; - std::map> _handlers; - std::shared_ptr _debug_handler; public: ffmpeg_manager(); ~ffmpeg_manager(); - void register_handler(std::string codec, std::shared_ptr handler); + streamfx::encoder::ffmpeg::handler* find_handler(std::string_view codec); - std::shared_ptr get_handler(std::string codec); + streamfx::encoder::ffmpeg::handler* get_handler(std::string_view codec); bool has_handler(std::string_view codec); diff --git a/source/encoders/ffmpeg/handler.cpp b/source/encoders/ffmpeg/handler.cpp index bded6951..272c22d4 100644 --- a/source/encoders/ffmpeg/handler.cpp +++ b/source/encoders/ffmpeg/handler.cpp @@ -1,41 +1,67 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END - #include "handler.hpp" #include "../encoder-ffmpeg.hpp" -using namespace streamfx::encoder::ffmpeg; +streamfx::encoder::ffmpeg::handler::handler_map_t& streamfx::encoder::ffmpeg::handler::handlers() +{ + static handler_map_t handlers; + return handlers; +} -bool handler::handler::has_keyframe_support(ffmpeg_factory* instance) +streamfx::encoder::ffmpeg::handler::handler(std::string codec) +{ + handlers().emplace(codec, this); +} + +bool streamfx::encoder::ffmpeg::handler::has_keyframes(ffmpeg_factory* factory) { #if LIBAVCODEC_VERSION_MAJOR > 58 - if (auto* desc = avcodec_descriptor_get(instance->get_avcodec()->id); desc) { + if (auto* desc = avcodec_descriptor_get(factory->get_avcodec()->id); desc) { return (desc->props & AV_CODEC_PROP_INTRA_ONLY) == 0; } else { return false; } #else - return (instance->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0; + return (factory->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0; #endif } -bool handler::handler::is_hardware_encoder(ffmpeg_factory* instance) +bool streamfx::encoder::ffmpeg::handler::has_threading(ffmpeg_factory* factory) { + return (factory->get_avcodec()->capabilities & (AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_OTHER_THREADS)); +} + +bool streamfx::encoder::ffmpeg::handler::is_hardware(ffmpeg_factory* factory) +{ + if (factory->get_avcodec()->capabilities & AV_CODEC_CAP_HARDWARE) { + return true; + } return false; } -bool handler::handler::has_threading_support(ffmpeg_factory* instance) -{ - return (instance->get_avcodec()->capabilities & (AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)); -} - -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) +bool streamfx::encoder::ffmpeg::handler::is_reconfigurable(ffmpeg_factory* factory, bool& threads, bool& gpu, bool& keyframes) { + if (factory->get_avcodec()->capabilities & AV_CODEC_CAP_PARAM_CHANGE) { + return true; + } return false; } + +void streamfx::encoder::ffmpeg::handler::adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec) {} + +std::string streamfx::encoder::ffmpeg::handler::help(ffmpeg_factory* factory) { + return "about:blank"; +} + +void streamfx::encoder::ffmpeg::handler::defaults(ffmpeg_factory* factory, obs_data_t* settings) {} + +void streamfx::encoder::ffmpeg::handler::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) {} + +void streamfx::encoder::ffmpeg::handler::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version) {} + +void streamfx::encoder::ffmpeg::handler::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) {} + +void streamfx::encoder::ffmpeg::handler::override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) {} + +void streamfx::encoder::ffmpeg::handler::log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) {} + +void streamfx::encoder::ffmpeg::handler::override_colorformat(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, AVPixelFormat target_format) {} diff --git a/source/encoders/ffmpeg/handler.hpp b/source/encoders/ffmpeg/handler.hpp index db83252a..79a3b39b 100644 --- a/source/encoders/ffmpeg/handler.hpp +++ b/source/encoders/ffmpeg/handler.hpp @@ -1,63 +1,42 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END - #pragma once -#include "common.hpp" -#include "ffmpeg/hwapi/base.hpp" - -extern "C" { #include "warning-disable.hpp" +#include +#include +#include +extern "C" { +#include #include -#include "warning-enable.hpp" } +#include "warning-enable.hpp" namespace streamfx::encoder::ffmpeg { - struct ffmpeg_info; class ffmpeg_factory; class ffmpeg_instance; - namespace handler { - class handler { - public: - virtual ~handler(){}; + struct handler { + handler(std::string codec); - public /*factory*/: - virtual void adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name, std::string& codec_id){}; + virtual bool has_keyframes(ffmpeg_factory* factory); + virtual bool has_threading(ffmpeg_factory* factory); + virtual bool is_hardware(ffmpeg_factory* factory); + virtual bool is_reconfigurable(ffmpeg_factory* factory, bool& threads, bool& gpu, bool& keyframes); - virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode){}; + virtual void adjust_info(ffmpeg_factory* factory, std::string& id, std::string& name, std::string& codec); - virtual std::string_view get_help_url(const AVCodec* codec) - { - return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg"; - }; + virtual std::string help(ffmpeg_factory* factory); - public /*support tests*/: - virtual bool has_keyframe_support(ffmpeg_factory* instance); + virtual void defaults(ffmpeg_factory* factory, obs_data_t* settings); + virtual void properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props); + virtual void migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version); + virtual void update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings); + virtual void override_update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings); + virtual void log(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings); - virtual bool is_hardware_encoder(ffmpeg_factory* instance); + virtual void override_colorformat(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, AVPixelFormat target_format); - virtual bool has_threading_support(ffmpeg_factory* instance); + public: + typedef std::map handler_map_t; - 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){}; - - public /*instance*/: - virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, AVCodecContext* context){}; - - virtual void process_avpacket(std::shared_ptr packet, const AVCodec* codec, AVCodecContext* context){}; - }; - } // namespace handler + static handler_map_t& handlers(); + }; } // namespace streamfx::encoder::ffmpeg