encoders/ffmpeg: Rebase onto obs::encoder_factory

This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-06-14 22:20:21 +02:00
parent d3c2f288b4
commit ce93f96a69
9 changed files with 611 additions and 918 deletions

View file

@ -378,6 +378,7 @@ Codec.ProRes.Profile.AP4X="4444 Extreme Quality/XQ (AP4X)"
# Encoder: FFmpeg # Encoder: FFmpeg
FFmpegEncoder="FFmpeg Options" FFmpegEncoder="FFmpeg Options"
FFmpegEncoder.Suffix=" (via FFmpeg)"
FFmpegEncoder.CustomSettings="Custom Settings" FFmpegEncoder.CustomSettings="Custom Settings"
FFmpegEncoder.CustomSettings.Description="Override any options shown (or not shown) above with your own.\nThe format is similar to that of the FFmpeg command line:\n -key=value -key2=value2 -key3='quoted value'" FFmpegEncoder.CustomSettings.Description="Override any options shown (or not shown) above with your own.\nThe format is similar to that of the FFmpeg command line:\n -key=value -key2=value2 -key3='quoted value'"
FFmpegEncoder.Threads="Number of Threads" FFmpegEncoder.Threads="Number of Threads"

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@
#include "ffmpeg/hwapi/base.hpp" #include "ffmpeg/hwapi/base.hpp"
#include "ffmpeg/swscale.hpp" #include "ffmpeg/swscale.hpp"
#include "handlers/handler.hpp" #include "handlers/handler.hpp"
#include "obs/obs-encoder-factory.hpp"
extern "C" { extern "C" {
#ifdef _MSC_VER #ifdef _MSC_VER
@ -49,54 +50,21 @@ extern "C" {
namespace streamfx::encoder::ffmpeg { namespace streamfx::encoder::ffmpeg {
class ffmpeg_factory; class ffmpeg_factory;
struct ffmpeg_info { class ffmpeg_instance : public obs::encoder_instance {
std::string uid;
std::string codec;
std::string readable_name;
obs_encoder_info oei = {0};
};
class ffmpeg_factory {
ffmpeg_info info;
ffmpeg_info info_fallback;
const AVCodec* avcodec_ptr;
std::shared_ptr<handler::handler> _handler;
public:
ffmpeg_factory(const AVCodec* codec);
virtual ~ffmpeg_factory();
void register_encoder();
void get_defaults(obs_data_t* settings, bool hw_encoder = false);
void get_properties(obs_properties_t* props, bool hw_encoder = false);
const AVCodec* get_avcodec();
const ffmpeg_info& get_info();
const ffmpeg_info& get_fallback();
};
class ffmpeg_instance {
obs_encoder_t* _self;
ffmpeg_factory* _factory; ffmpeg_factory* _factory;
const AVCodec* _codec; const AVCodec* _codec;
AVCodecContext* _context; AVCodecContext* _context;
std::shared_ptr<handler::handler> _handler; std::shared_ptr<handler::handler> _handler;
::ffmpeg::swscale _scaler;
AVPacket _packet;
std::shared_ptr<::ffmpeg::hwapi::base> _hwapi; std::shared_ptr<::ffmpeg::hwapi::base> _hwapi;
std::shared_ptr<::ffmpeg::hwapi::instance> _hwinst; std::shared_ptr<::ffmpeg::hwapi::instance> _hwinst;
::ffmpeg::swscale _swscale;
AVPacket _current_packet;
std::size_t _lag_in_frames; std::size_t _lag_in_frames;
std::size_t _count_send_frames; std::size_t _sent_frames;
// Extra Data // Extra Data
bool _have_first_frame; bool _have_first_frame;
@ -108,6 +76,31 @@ namespace streamfx::encoder::ffmpeg {
std::queue<std::shared_ptr<AVFrame>> _used_frames; std::queue<std::shared_ptr<AVFrame>> _used_frames;
std::chrono::high_resolution_clock::time_point _free_frames_last_used; std::chrono::high_resolution_clock::time_point _free_frames_last_used;
public:
ffmpeg_instance(obs_data_t* settings, obs_encoder_t* self);
virtual ~ffmpeg_instance();
public:
void get_properties(obs_properties_t* props);
void migrate(obs_data_t* settings, std::uint64_t version) override;
bool update(obs_data_t* settings) override;
bool encode_audio(struct encoder_frame* frame, struct encoder_packet* packet, bool* received_packet) override;
bool encode_video(struct encoder_frame* frame, struct encoder_packet* packet, bool* received_packet) override;
bool encode_video(uint32_t handle, int64_t pts, uint64_t lock_key, uint64_t* next_key,
struct encoder_packet* packet, bool* received_packet) override;
bool get_extra_data(uint8_t** extra_data, size_t* size) override;
bool get_sei_data(uint8_t** sei_data, size_t* size) override;
void get_video_info(struct video_scale_info* info) override;
public:
void initialize_sw(obs_data_t* settings); void initialize_sw(obs_data_t* settings);
void initialize_hw(obs_data_t* settings); void initialize_hw(obs_data_t* settings);
@ -117,35 +110,6 @@ namespace streamfx::encoder::ffmpeg {
void push_used_frame(std::shared_ptr<AVFrame> frame); void push_used_frame(std::shared_ptr<AVFrame> frame);
std::shared_ptr<AVFrame> pop_used_frame(); std::shared_ptr<AVFrame> pop_used_frame();
public:
ffmpeg_instance(obs_data_t* settings, obs_encoder_t* encoder, bool is_texture_encode = false);
virtual ~ffmpeg_instance();
public: // OBS API
// Shared
void get_properties(obs_properties_t* props, bool hw_encode = false);
bool update(obs_data_t* settings);
// Audio only
void get_audio_info(struct audio_convert_info* info);
std::size_t get_frame_size();
bool audio_encode(struct encoder_frame* frame, struct encoder_packet* packet, bool* received_packet);
// Video only
void get_video_info(struct video_scale_info* info);
bool get_sei_data(std::uint8_t** sei_data, size_t* size);
bool get_extra_data(std::uint8_t** extra_data, size_t* size);
bool video_encode(struct encoder_frame* frame, struct encoder_packet* packet, bool* received_packet);
bool video_encode_texture(std::uint32_t handle, std::int64_t pts, std::uint64_t lock_key,
std::uint64_t* next_key, struct encoder_packet* packet, bool* received_packet);
int receive_packet(bool* received_packet, struct encoder_packet* packet); int receive_packet(bool* received_packet, struct encoder_packet* packet);
int send_frame(std::shared_ptr<AVFrame> frame); int send_frame(std::shared_ptr<AVFrame> frame);
@ -162,6 +126,29 @@ namespace streamfx::encoder::ffmpeg {
void parse_ffmpeg_commandline(std::string text); void parse_ffmpeg_commandline(std::string text);
}; };
class ffmpeg_factory : public obs::encoder_factory<ffmpeg_factory, ffmpeg_instance> {
std::string _id;
std::string _codec;
std::string _name;
const AVCodec* _avcodec;
std::shared_ptr<handler::handler> _handler;
public:
ffmpeg_factory(const AVCodec* codec);
virtual ~ffmpeg_factory();
const char* get_name() override;
void get_defaults2(obs_data_t* data) override;
obs_properties_t* get_properties2(instance_t* data) override;
public:
const AVCodec* get_avcodec();
};
class ffmpeg_manager { class ffmpeg_manager {
std::map<const AVCodec*, std::shared_ptr<ffmpeg_factory>> _factories; std::map<const AVCodec*, std::shared_ptr<ffmpeg_factory>> _factories;
std::map<std::string, std::shared_ptr<handler::handler>> _handlers; std::map<std::string, std::shared_ptr<handler::handler>> _handlers;
@ -171,14 +158,14 @@ namespace streamfx::encoder::ffmpeg {
ffmpeg_manager(); ffmpeg_manager();
~ffmpeg_manager(); ~ffmpeg_manager();
void register_encoders();
void register_handler(std::string codec, std::shared_ptr<handler::handler> handler); void register_handler(std::string codec, std::shared_ptr<handler::handler> handler);
std::shared_ptr<handler::handler> get_handler(std::string codec); std::shared_ptr<handler::handler> get_handler(std::string codec);
bool has_handler(std::string codec); bool has_handler(std::string codec);
void register_encoders();
public: // Singleton public: // Singleton
static void initialize(); static void initialize();

View file

@ -24,10 +24,6 @@
using namespace streamfx::encoder::ffmpeg; using namespace streamfx::encoder::ffmpeg;
void handler::handler::adjust_encoder_info(ffmpeg_factory*, ffmpeg_info*, ffmpeg_info*) {}
void handler::handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
bool handler::handler::has_keyframe_support(ffmpeg_factory* instance) bool handler::handler::has_keyframe_support(ffmpeg_factory* instance)
{ {
return (instance->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0; return (instance->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0;
@ -47,15 +43,3 @@ bool handler::handler::has_pixel_format_support(ffmpeg_factory* instance)
{ {
return (instance->get_avcodec()->pix_fmts != nullptr); return (instance->get_avcodec()->pix_fmts != nullptr);
} }
void handler::handler::get_properties(obs_properties_t*, const AVCodec*, AVCodecContext*, bool) {}
void handler::handler::update(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void handler::handler::override_update(ffmpeg_instance*, obs_data_t*) {}
void handler::handler::log_options(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void handler::handler::override_colorformat(AVPixelFormat&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
void handler::handler::process_avpacket(AVPacket&, const AVCodec*, AVCodecContext*) {}

View file

@ -41,10 +41,11 @@ namespace streamfx::encoder::ffmpeg {
virtual ~handler(){}; virtual ~handler(){};
public /*factory*/: public /*factory*/:
virtual void adjust_encoder_info(ffmpeg_factory* factory, ffmpeg_info* main, ffmpeg_info* fallback); 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, virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode); bool hw_encode){};
public /*support tests*/: public /*support tests*/:
virtual bool has_keyframe_support(ffmpeg_factory* instance); virtual bool has_keyframe_support(ffmpeg_factory* instance);
@ -57,20 +58,20 @@ namespace streamfx::encoder::ffmpeg {
public /*settings*/: public /*settings*/:
virtual void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, virtual void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context,
bool hw_encode); bool hw_encode){};
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(ffmpeg_instance* instance, obs_data_t* settings); virtual void override_update(ffmpeg_instance* 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){};
public /*instance*/: public /*instance*/:
virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context); AVCodecContext* context){};
virtual void process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context); virtual void process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context){};
}; };
} // namespace handler } // namespace handler
} // namespace streamfx::encoder::ffmpeg } // namespace streamfx::encoder::ffmpeg

View file

@ -60,11 +60,9 @@ std::map<level, std::string> levels{
{level::L5_1, "5.1"}, {level::L5_2, "5.2"}, {level::L5_1, "5.1"}, {level::L5_2, "5.2"},
}; };
void nvenc_h264_handler::adjust_encoder_info(ffmpeg_factory*, ffmpeg_info* main, ffmpeg_info* fallback) void nvenc_h264_handler::adjust_info(ffmpeg_factory*, const AVCodec*, std::string&, std::string& name, std::string&)
{ {
main->readable_name = "H.264/AVC NVidia NVENC"; name = "NVIDIA NVENC H.264/AVC Encoder";
fallback->readable_name = "H.264/AVC NVidia NVENC (Software Fallback)";
fallback->oei.caps |= OBS_ENCODER_CAP_DEPRECATED;
} }
void nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool) void nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool)

View file

@ -35,7 +35,8 @@ namespace streamfx::encoder::ffmpeg::handler {
virtual ~nvenc_h264_handler(){}; virtual ~nvenc_h264_handler(){};
public /*factory*/: public /*factory*/:
virtual void adjust_encoder_info(ffmpeg_factory* factory, ffmpeg_info* main, ffmpeg_info* fallback); 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 void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);

View file

@ -60,11 +60,9 @@ std::map<level, std::string> levels{
{level::L6_0, "6.0"}, {level::L6_1, "6.1"}, {level::L6_2, "6.2"}, {level::L6_0, "6.0"}, {level::L6_1, "6.1"}, {level::L6_2, "6.2"},
}; };
void nvenc_hevc_handler::adjust_encoder_info(ffmpeg_factory*, ffmpeg_info* main, ffmpeg_info* fallback) void nvenc_hevc_handler::adjust_info(ffmpeg_factory*, const AVCodec*, std::string&, std::string& name, std::string&)
{ {
main->readable_name = "H.265/HEVC Nvidia NVENC"; name = "NVIDIA NVENC H.265/HEVC Encoder";
fallback->readable_name = "H.265/HEVC Nvidia NVENC (Software Fallback)";
fallback->oei.caps |= OBS_ENCODER_CAP_DEPRECATED;
} }
void nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool) void nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool)

View file

@ -35,7 +35,8 @@ namespace streamfx::encoder::ffmpeg::handler {
virtual ~nvenc_hevc_handler(){}; virtual ~nvenc_hevc_handler(){};
public /*factory*/: public /*factory*/:
virtual void adjust_encoder_info(ffmpeg_factory* factory, ffmpeg_info* main, ffmpeg_info* fallback); 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 void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);