refactor(video): move encoder declarations to header (#2185)

This commit is contained in:
ReenigneArcher
2024-03-16 09:04:29 -04:00
committed by GitHub
parent bd5c50041c
commit 7534fa1023
2 changed files with 179 additions and 150 deletions

View File

@@ -14,7 +14,6 @@ extern "C" {
#include <libavutil/mastering_display_metadata.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libswscale/swscale.h>
}
#include "cbs.h"
@@ -51,12 +50,6 @@ namespace video {
av_buffer_unref(&ref);
}
using avcodec_ctx_t = util::safe_ptr<AVCodecContext, free_ctx>;
using avcodec_frame_t = util::safe_ptr<AVFrame, free_frame>;
using avcodec_buffer_t = util::safe_ptr<AVBufferRef, free_buffer>;
using sws_t = util::safe_ptr<SwsContext, sws_freeContext>;
using img_event_t = std::shared_ptr<safe::event_t<std::shared_ptr<platf::img_t>>>;
namespace nv {
enum class profile_h264_e : int {
@@ -87,11 +80,6 @@ namespace video {
};
} // namespace qsv
platf::mem_type_e
map_base_dev_type(AVHWDeviceType type);
platf::pix_fmt_e
map_pix_fmt(AVPixelFormat fmt);
util::Either<avcodec_buffer_t, int>
dxgi_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *);
util::Either<avcodec_buffer_t, int>
@@ -288,137 +276,6 @@ namespace video {
ALWAYS_REPROBE = 1 << 9, // This is an encoder of last resort and we want to aggressively probe for a better one
};
struct encoder_platform_formats_t {
virtual ~encoder_platform_formats_t() = default;
platf::mem_type_e dev_type;
platf::pix_fmt_e pix_fmt_8bit, pix_fmt_10bit;
};
struct encoder_platform_formats_avcodec: encoder_platform_formats_t {
using init_buffer_function_t = std::function<util::Either<avcodec_buffer_t, int>(platf::avcodec_encode_device_t *)>;
encoder_platform_formats_avcodec(
const AVHWDeviceType &avcodec_base_dev_type,
const AVHWDeviceType &avcodec_derived_dev_type,
const AVPixelFormat &avcodec_dev_pix_fmt,
const AVPixelFormat &avcodec_pix_fmt_8bit,
const AVPixelFormat &avcodec_pix_fmt_10bit,
const init_buffer_function_t &init_avcodec_hardware_input_buffer_function):
avcodec_base_dev_type { avcodec_base_dev_type },
avcodec_derived_dev_type { avcodec_derived_dev_type },
avcodec_dev_pix_fmt { avcodec_dev_pix_fmt },
avcodec_pix_fmt_8bit { avcodec_pix_fmt_8bit },
avcodec_pix_fmt_10bit { avcodec_pix_fmt_10bit },
init_avcodec_hardware_input_buffer { init_avcodec_hardware_input_buffer_function } {
dev_type = map_base_dev_type(avcodec_base_dev_type);
pix_fmt_8bit = map_pix_fmt(avcodec_pix_fmt_8bit);
pix_fmt_10bit = map_pix_fmt(avcodec_pix_fmt_10bit);
}
AVHWDeviceType avcodec_base_dev_type, avcodec_derived_dev_type;
AVPixelFormat avcodec_dev_pix_fmt;
AVPixelFormat avcodec_pix_fmt_8bit, avcodec_pix_fmt_10bit;
init_buffer_function_t init_avcodec_hardware_input_buffer;
};
struct encoder_platform_formats_nvenc: encoder_platform_formats_t {
encoder_platform_formats_nvenc(
const platf::mem_type_e &dev_type,
const platf::pix_fmt_e &pix_fmt_8bit,
const platf::pix_fmt_e &pix_fmt_10bit) {
encoder_platform_formats_t::dev_type = dev_type;
encoder_platform_formats_t::pix_fmt_8bit = pix_fmt_8bit;
encoder_platform_formats_t::pix_fmt_10bit = pix_fmt_10bit;
}
};
struct encoder_t {
std::string_view name;
enum flag_e {
PASSED, // Is supported
REF_FRAMES_RESTRICT, // Set maximum reference frames
CBR, // Some encoders don't support CBR, if not supported --> attempt constant quantatication parameter instead
DYNAMIC_RANGE, // hdr
VUI_PARAMETERS, // AMD encoder with VAAPI doesn't add VUI parameters to SPS
MAX_FLAGS
};
static std::string_view
from_flag(flag_e flag) {
#define _CONVERT(x) \
case flag_e::x: \
return #x##sv
switch (flag) {
_CONVERT(PASSED);
_CONVERT(REF_FRAMES_RESTRICT);
_CONVERT(CBR);
_CONVERT(DYNAMIC_RANGE);
_CONVERT(VUI_PARAMETERS);
_CONVERT(MAX_FLAGS);
}
#undef _CONVERT
return "unknown"sv;
}
struct option_t {
KITTY_DEFAULT_CONSTR_MOVE(option_t)
option_t(const option_t &) = default;
std::string name;
std::variant<int, int *, std::optional<int> *, std::function<int()>, std::string, std::string *> value;
option_t(std::string &&name, decltype(value) &&value):
name { std::move(name) }, value { std::move(value) } {}
};
const std::unique_ptr<const encoder_platform_formats_t> platform_formats;
struct {
std::vector<option_t> common_options;
std::vector<option_t> sdr_options;
std::vector<option_t> hdr_options;
std::vector<option_t> fallback_options;
// QP option to set in the case that CBR/VBR is not supported
// by the encoder. If CBR/VBR is guaranteed to be supported,
// don't specify this option to avoid wasteful encoder probing.
std::optional<option_t> qp;
std::string name;
std::bitset<MAX_FLAGS> capabilities;
bool
operator[](flag_e flag) const {
return capabilities[(std::size_t) flag];
}
std::bitset<MAX_FLAGS>::reference
operator[](flag_e flag) {
return capabilities[(std::size_t) flag];
}
} av1, hevc, h264;
uint32_t flags;
};
struct encode_session_t {
virtual ~encode_session_t() = default;
virtual int
convert(platf::img_t &img) = 0;
virtual void
request_idr_frame() = 0;
virtual void
request_normal_frame() = 0;
virtual void
invalidate_ref_frames(int64_t first_frame, int64_t last_frame) = 0;
};
class avcodec_encode_session_t: public encode_session_t {
public:
avcodec_encode_session_t() = default;
@@ -586,7 +443,7 @@ namespace video {
auto capture_thread_sync = safe::make_shared<capture_thread_sync_ctx_t>(start_capture_sync, end_capture_sync);
#ifdef _WIN32
static encoder_t nvenc {
encoder_t nvenc {
"nvenc"sv,
std::make_unique<encoder_platform_formats_nvenc>(
platf::mem_type_e::dxgi,
@@ -630,7 +487,7 @@ namespace video {
PARALLEL_ENCODING | REF_FRAMES_INVALIDATION // flags
};
#elif !defined(__APPLE__)
static encoder_t nvenc {
encoder_t nvenc {
"nvenc"sv,
std::make_unique<encoder_platform_formats_avcodec>(
#ifdef _WIN32
@@ -718,7 +575,7 @@ namespace video {
#endif
#ifdef _WIN32
static encoder_t quicksync {
encoder_t quicksync {
"quicksync"sv,
std::make_unique<encoder_platform_formats_avcodec>(
AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_QSV,
@@ -799,7 +656,7 @@ namespace video {
PARALLEL_ENCODING | CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT
};
static encoder_t amdvce {
encoder_t amdvce {
"amdvce"sv,
std::make_unique<encoder_platform_formats_avcodec>(
AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_NONE,
@@ -871,7 +728,7 @@ namespace video {
};
#endif
static encoder_t software {
encoder_t software {
"software"sv,
std::make_unique<encoder_platform_formats_avcodec>(
AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_NONE,
@@ -936,7 +793,7 @@ namespace video {
};
#ifdef __linux__
static encoder_t vaapi {
encoder_t vaapi {
"vaapi"sv,
std::make_unique<encoder_platform_formats_avcodec>(
AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_NONE,
@@ -1004,7 +861,7 @@ namespace video {
#endif
#ifdef __APPLE__
static encoder_t videotoolbox {
encoder_t videotoolbox {
"videotoolbox"sv,
std::make_unique<encoder_platform_formats_avcodec>(
AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_NONE,

View File

@@ -11,11 +11,181 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
struct AVPacket;
namespace video {
platf::mem_type_e
map_base_dev_type(AVHWDeviceType type);
platf::pix_fmt_e
map_pix_fmt(AVPixelFormat fmt);
void
free_ctx(AVCodecContext *ctx);
void
free_frame(AVFrame *frame);
void
free_buffer(AVBufferRef *ref);
using avcodec_ctx_t = util::safe_ptr<AVCodecContext, free_ctx>;
using avcodec_frame_t = util::safe_ptr<AVFrame, free_frame>;
using avcodec_buffer_t = util::safe_ptr<AVBufferRef, free_buffer>;
using sws_t = util::safe_ptr<SwsContext, sws_freeContext>;
using img_event_t = std::shared_ptr<safe::event_t<std::shared_ptr<platf::img_t>>>;
struct encoder_platform_formats_t {
virtual ~encoder_platform_formats_t() = default;
platf::mem_type_e dev_type;
platf::pix_fmt_e pix_fmt_8bit, pix_fmt_10bit;
};
struct encoder_platform_formats_avcodec: encoder_platform_formats_t {
using init_buffer_function_t = std::function<util::Either<avcodec_buffer_t, int>(platf::avcodec_encode_device_t *)>;
encoder_platform_formats_avcodec(
const AVHWDeviceType &avcodec_base_dev_type,
const AVHWDeviceType &avcodec_derived_dev_type,
const AVPixelFormat &avcodec_dev_pix_fmt,
const AVPixelFormat &avcodec_pix_fmt_8bit,
const AVPixelFormat &avcodec_pix_fmt_10bit,
const init_buffer_function_t &init_avcodec_hardware_input_buffer_function):
avcodec_base_dev_type { avcodec_base_dev_type },
avcodec_derived_dev_type { avcodec_derived_dev_type },
avcodec_dev_pix_fmt { avcodec_dev_pix_fmt },
avcodec_pix_fmt_8bit { avcodec_pix_fmt_8bit },
avcodec_pix_fmt_10bit { avcodec_pix_fmt_10bit },
init_avcodec_hardware_input_buffer { init_avcodec_hardware_input_buffer_function } {
dev_type = map_base_dev_type(avcodec_base_dev_type);
pix_fmt_8bit = map_pix_fmt(avcodec_pix_fmt_8bit);
pix_fmt_10bit = map_pix_fmt(avcodec_pix_fmt_10bit);
}
AVHWDeviceType avcodec_base_dev_type, avcodec_derived_dev_type;
AVPixelFormat avcodec_dev_pix_fmt;
AVPixelFormat avcodec_pix_fmt_8bit, avcodec_pix_fmt_10bit;
init_buffer_function_t init_avcodec_hardware_input_buffer;
};
struct encoder_platform_formats_nvenc: encoder_platform_formats_t {
encoder_platform_formats_nvenc(
const platf::mem_type_e &dev_type,
const platf::pix_fmt_e &pix_fmt_8bit,
const platf::pix_fmt_e &pix_fmt_10bit) {
encoder_platform_formats_t::dev_type = dev_type;
encoder_platform_formats_t::pix_fmt_8bit = pix_fmt_8bit;
encoder_platform_formats_t::pix_fmt_10bit = pix_fmt_10bit;
}
};
struct encoder_t {
std::string_view name;
enum flag_e {
PASSED, // Is supported
REF_FRAMES_RESTRICT, // Set maximum reference frames
CBR, // Some encoders don't support CBR, if not supported --> attempt constant quantatication parameter instead
DYNAMIC_RANGE, // hdr
VUI_PARAMETERS, // AMD encoder with VAAPI doesn't add VUI parameters to SPS
MAX_FLAGS
};
static std::string_view
from_flag(flag_e flag) {
#define _CONVERT(x) \
case flag_e::x: \
std::string_view(#x)
switch (flag) {
_CONVERT(PASSED);
_CONVERT(REF_FRAMES_RESTRICT);
_CONVERT(CBR);
_CONVERT(DYNAMIC_RANGE);
_CONVERT(VUI_PARAMETERS);
_CONVERT(MAX_FLAGS);
}
#undef _CONVERT
return { "unknown" };
}
struct option_t {
KITTY_DEFAULT_CONSTR_MOVE(option_t)
option_t(const option_t &) = default;
std::string name;
std::variant<int, int *, std::optional<int> *, std::function<int()>, std::string, std::string *> value;
option_t(std::string &&name, decltype(value) &&value):
name { std::move(name) }, value { std::move(value) } {}
};
const std::unique_ptr<const encoder_platform_formats_t> platform_formats;
struct codec_t {
std::vector<option_t> common_options;
std::vector<option_t> sdr_options;
std::vector<option_t> hdr_options;
std::vector<option_t> fallback_options;
// QP option to set in the case that CBR/VBR is not supported
// by the encoder. If CBR/VBR is guaranteed to be supported,
// don't specify this option to avoid wasteful encoder probing.
std::optional<option_t> qp;
std::string name;
std::bitset<MAX_FLAGS> capabilities;
bool
operator[](flag_e flag) const {
return capabilities[(std::size_t) flag];
}
std::bitset<MAX_FLAGS>::reference
operator[](flag_e flag) {
return capabilities[(std::size_t) flag];
}
} av1, hevc, h264;
uint32_t flags;
};
struct encode_session_t {
virtual ~encode_session_t() = default;
virtual int
convert(platf::img_t &img) = 0;
virtual void
request_idr_frame() = 0;
virtual void
request_normal_frame() = 0;
virtual void
invalidate_ref_frames(int64_t first_frame, int64_t last_frame) = 0;
};
// encoders
extern encoder_t software;
#if !defined(__APPLE__)
extern encoder_t nvenc; // available for windows and linux
#endif
#ifdef _WIN32
extern encoder_t amdvce;
extern encoder_t quicksync;
#endif
#ifdef __linux__
extern encoder_t vaapi;
#endif
#ifdef __APPLE__
extern encoder_t videotoolbox;
#endif
struct packet_raw_t {
virtual ~packet_raw_t() = default;
@@ -154,6 +324,8 @@ namespace video {
config_t config,
void *channel_data);
bool
validate_encoder(encoder_t &encoder, bool expect_failure);
int
probe_encoders();
} // namespace video