mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
feat(win/video): support native YUV 4:4:4 encoding (#2533)
This commit is contained in:
329
src/video.cpp
329
src/video.cpp
@@ -53,31 +53,36 @@ namespace video {
|
||||
namespace nv {
|
||||
|
||||
enum class profile_h264_e : int {
|
||||
baseline, ///< Baseline profile
|
||||
main, ///< Main profile
|
||||
high, ///< High profile
|
||||
high_444p, ///< High 4:4:4 Predictive profile
|
||||
high = 2, ///< High profile
|
||||
high_444p = 3, ///< High 4:4:4 Predictive profile
|
||||
};
|
||||
|
||||
enum class profile_hevc_e : int {
|
||||
main, ///< Main profile
|
||||
main_10, ///< Main 10 profile
|
||||
rext, ///< Rext profile
|
||||
main = 0, ///< Main profile
|
||||
main_10 = 1, ///< Main 10 profile
|
||||
rext = 2, ///< Rext profile
|
||||
};
|
||||
|
||||
} // namespace nv
|
||||
|
||||
namespace qsv {
|
||||
|
||||
enum class profile_h264_e : int {
|
||||
baseline = 66, ///< Baseline profile
|
||||
main = 77, ///< Main profile
|
||||
high = 100, ///< High profile
|
||||
high_444p = 244, ///< High 4:4:4 Predictive profile
|
||||
};
|
||||
|
||||
enum class profile_hevc_e : int {
|
||||
main = 1, ///< Main profile
|
||||
main_10 = 2, ///< Main 10 profile
|
||||
rext = 4, ///< RExt profile
|
||||
};
|
||||
|
||||
enum class profile_av1_e : int {
|
||||
main = 1, ///< Main profile
|
||||
high = 2, ///< High profile
|
||||
};
|
||||
|
||||
} // namespace qsv
|
||||
|
||||
util::Either<avcodec_buffer_t, int>
|
||||
@@ -274,6 +279,7 @@ namespace video {
|
||||
NO_RC_BUF_LIMIT = 1 << 7, ///< Don't set rc_buffer_size
|
||||
REF_FRAMES_INVALIDATION = 1 << 8, ///< Support reference frames invalidation
|
||||
ALWAYS_REPROBE = 1 << 9, ///< This is an encoder of last resort and we want to aggressively probe for a better one
|
||||
YUV444_SUPPORT = 1 << 10, ///< Encoder may support 4:4:4 chroma sampling depending on hardware
|
||||
};
|
||||
|
||||
class avcodec_encode_session_t: public encode_session_t {
|
||||
@@ -447,44 +453,39 @@ namespace video {
|
||||
"nvenc"sv,
|
||||
std::make_unique<encoder_platform_formats_nvenc>(
|
||||
platf::mem_type_e::dxgi,
|
||||
platf::pix_fmt_e::nv12, platf::pix_fmt_e::p010),
|
||||
platf::pix_fmt_e::nv12, platf::pix_fmt_e::p010,
|
||||
platf::pix_fmt_e::ayuv, platf::pix_fmt_e::yuv444p16),
|
||||
{
|
||||
// Common options
|
||||
{},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{},
|
||||
{}, // Common options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"av1_nvenc"s,
|
||||
},
|
||||
{
|
||||
// Common options
|
||||
{},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{},
|
||||
{}, // Common options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"hevc_nvenc"s,
|
||||
},
|
||||
{
|
||||
// Common options
|
||||
{},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{},
|
||||
{}, // Common options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"h264_nvenc"s,
|
||||
},
|
||||
PARALLEL_ENCODING | REF_FRAMES_INVALIDATION // flags
|
||||
PARALLEL_ENCODING | REF_FRAMES_INVALIDATION | YUV444_SUPPORT // flags
|
||||
};
|
||||
#elif !defined(__APPLE__)
|
||||
encoder_t nvenc {
|
||||
@@ -498,6 +499,7 @@ namespace video {
|
||||
AV_PIX_FMT_CUDA,
|
||||
#endif
|
||||
AV_PIX_FMT_NV12, AV_PIX_FMT_P010,
|
||||
AV_PIX_FMT_NONE, AV_PIX_FMT_NONE,
|
||||
#ifdef _WIN32
|
||||
dxgi_init_avcodec_hardware_input_buffer
|
||||
#else
|
||||
@@ -516,12 +518,11 @@ namespace video {
|
||||
{ "multipass"s, &config::video.nv_legacy.multipass },
|
||||
{ "aq"s, &config::video.nv_legacy.aq },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"av1_nvenc"s,
|
||||
},
|
||||
@@ -537,14 +538,16 @@ namespace video {
|
||||
{ "multipass"s, &config::video.nv_legacy.multipass },
|
||||
{ "aq"s, &config::video.nv_legacy.aq },
|
||||
},
|
||||
// SDR-specific options
|
||||
{
|
||||
// SDR-specific options
|
||||
{ "profile"s, (int) nv::profile_hevc_e::main },
|
||||
},
|
||||
// HDR-specific options
|
||||
{
|
||||
// HDR-specific options
|
||||
{ "profile"s, (int) nv::profile_hevc_e::main_10 },
|
||||
},
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"hevc_nvenc"s,
|
||||
@@ -561,11 +564,13 @@ namespace video {
|
||||
{ "multipass"s, &config::video.nv_legacy.multipass },
|
||||
{ "aq"s, &config::video.nv_legacy.aq },
|
||||
},
|
||||
// SDR-specific options
|
||||
{
|
||||
// SDR-specific options
|
||||
{ "profile"s, (int) nv::profile_h264_e::high },
|
||||
},
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"h264_nvenc"s,
|
||||
@@ -581,6 +586,7 @@ namespace video {
|
||||
AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_QSV,
|
||||
AV_PIX_FMT_QSV,
|
||||
AV_PIX_FMT_NV12, AV_PIX_FMT_P010,
|
||||
AV_PIX_FMT_VUYX, AV_PIX_FMT_XV30,
|
||||
dxgi_init_avcodec_hardware_input_buffer),
|
||||
{
|
||||
// Common options
|
||||
@@ -591,12 +597,23 @@ namespace video {
|
||||
{ "low_delay_brc"s, 1 },
|
||||
{ "low_power"s, 1 },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{},
|
||||
{
|
||||
// SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_av1_e::main },
|
||||
},
|
||||
{
|
||||
// HDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_av1_e::main },
|
||||
},
|
||||
{
|
||||
// YUV444 SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_av1_e::high },
|
||||
},
|
||||
{
|
||||
// YUV444 HDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_av1_e::high },
|
||||
},
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"av1_qsv"s,
|
||||
},
|
||||
@@ -611,16 +628,24 @@ namespace video {
|
||||
{ "recovery_point_sei"s, 0 },
|
||||
{ "pic_timing_sei"s, 0 },
|
||||
},
|
||||
// SDR-specific options
|
||||
{
|
||||
// SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_hevc_e::main },
|
||||
},
|
||||
// HDR-specific options
|
||||
{
|
||||
// HDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_hevc_e::main_10 },
|
||||
},
|
||||
// Fallback options
|
||||
{
|
||||
// YUV444 SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_hevc_e::rext },
|
||||
},
|
||||
{
|
||||
// YUV444 HDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_hevc_e::rext },
|
||||
},
|
||||
{
|
||||
// Fallback options
|
||||
{ "low_power"s, []() { return config::video.qsv.qsv_slow_hevc ? 0 : 1; } },
|
||||
},
|
||||
std::nullopt, // QP rate control fallback
|
||||
@@ -640,20 +665,24 @@ namespace video {
|
||||
{ "pic_timing_sei"s, 0 },
|
||||
{ "max_dec_frame_buffering"s, 1 },
|
||||
},
|
||||
// SDR-specific options
|
||||
{
|
||||
// SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_h264_e::high },
|
||||
},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{}, // HDR-specific options
|
||||
{
|
||||
// YUV444 SDR-specific options
|
||||
{ "profile"s, (int) qsv::profile_h264_e::high_444p },
|
||||
},
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "low_power"s, 0 }, // Some old/low-end Intel GPUs don't support low power encoding
|
||||
},
|
||||
std::nullopt, // QP rate control fallback
|
||||
"h264_qsv"s,
|
||||
},
|
||||
PARALLEL_ENCODING | CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT
|
||||
PARALLEL_ENCODING | CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT | YUV444_SUPPORT
|
||||
};
|
||||
|
||||
encoder_t amdvce {
|
||||
@@ -662,6 +691,7 @@ namespace video {
|
||||
AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_NONE,
|
||||
AV_PIX_FMT_D3D11,
|
||||
AV_PIX_FMT_NV12, AV_PIX_FMT_P010,
|
||||
AV_PIX_FMT_NONE, AV_PIX_FMT_NONE,
|
||||
dxgi_init_avcodec_hardware_input_buffer),
|
||||
{
|
||||
// Common options
|
||||
@@ -676,6 +706,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"av1_amf"s,
|
||||
@@ -698,6 +730,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"hevc_amf"s,
|
||||
@@ -716,12 +750,12 @@ namespace video {
|
||||
{ "vbaq"s, &config::video.amd.amd_vbaq },
|
||||
{ "enforce_hrd"s, &config::video.amd.amd_enforce_hrd },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "usage"s, 2 /* AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY */ }, // Workaround for https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/410
|
||||
},
|
||||
std::nullopt, // QP rate control fallback
|
||||
@@ -737,6 +771,7 @@ namespace video {
|
||||
AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_NONE,
|
||||
AV_PIX_FMT_NONE,
|
||||
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10,
|
||||
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10,
|
||||
nullptr),
|
||||
{
|
||||
// libsvtav1 takes different presets than libx264/libx265.
|
||||
@@ -749,6 +784,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
|
||||
// QP rate control fallback
|
||||
@@ -776,6 +813,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"libx265"s,
|
||||
@@ -788,11 +827,13 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt, // QP rate control fallback
|
||||
"libx264"s,
|
||||
},
|
||||
H264_ONLY | PARALLEL_ENCODING | ALWAYS_REPROBE
|
||||
H264_ONLY | PARALLEL_ENCODING | ALWAYS_REPROBE | YUV444_SUPPORT
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -802,6 +843,7 @@ namespace video {
|
||||
AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_NONE,
|
||||
AV_PIX_FMT_VAAPI,
|
||||
AV_PIX_FMT_NV12, AV_PIX_FMT_P010,
|
||||
AV_PIX_FMT_NONE, AV_PIX_FMT_NONE,
|
||||
vaapi_init_avcodec_hardware_input_buffer),
|
||||
{
|
||||
// Common options
|
||||
@@ -810,12 +852,12 @@ namespace video {
|
||||
{ "async_depth"s, 1 },
|
||||
{ "idr_interval"s, std::numeric_limits<int>::max() },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints
|
||||
},
|
||||
std::make_optional<encoder_t::option_t>("qp"s, &config::video.qp),
|
||||
@@ -829,12 +871,12 @@ namespace video {
|
||||
{ "sei"s, 0 },
|
||||
{ "idr_interval"s, std::numeric_limits<int>::max() },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints
|
||||
},
|
||||
std::make_optional<encoder_t::option_t>("qp"s, &config::video.qp),
|
||||
@@ -848,12 +890,12 @@ namespace video {
|
||||
{ "sei"s, 0 },
|
||||
{ "idr_interval"s, std::numeric_limits<int>::max() },
|
||||
},
|
||||
// SDR-specific options
|
||||
{},
|
||||
// HDR-specific options
|
||||
{},
|
||||
// Fallback options
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "low_power"s, 0 }, // Not all VAAPI drivers expose LP entrypoints
|
||||
},
|
||||
std::make_optional<encoder_t::option_t>("qp"s, &config::video.qp),
|
||||
@@ -871,6 +913,7 @@ namespace video {
|
||||
AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_NONE,
|
||||
AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
AV_PIX_FMT_NV12, AV_PIX_FMT_P010,
|
||||
AV_PIX_FMT_NONE, AV_PIX_FMT_NONE,
|
||||
vt_init_avcodec_hardware_input_buffer),
|
||||
{
|
||||
// Common options
|
||||
@@ -882,6 +925,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt,
|
||||
"av1_videotoolbox"s,
|
||||
@@ -896,6 +941,8 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{}, // Fallback options
|
||||
std::nullopt,
|
||||
"hevc_videotoolbox"s,
|
||||
@@ -910,9 +957,12 @@ namespace video {
|
||||
},
|
||||
{}, // SDR-specific options
|
||||
{}, // HDR-specific options
|
||||
{}, // YUV444 SDR-specific options
|
||||
{}, // YUV444 HDR-specific options
|
||||
{
|
||||
// Fallback options
|
||||
{ "flags"s, "-low_delay" },
|
||||
}, // Fallback options
|
||||
},
|
||||
std::nullopt,
|
||||
"h264_videotoolbox"s,
|
||||
},
|
||||
@@ -941,6 +991,7 @@ namespace video {
|
||||
int active_hevc_mode;
|
||||
int active_av1_mode;
|
||||
bool last_encoder_probe_supported_ref_frames_invalidation = false;
|
||||
std::array<bool, 3> last_encoder_probe_supported_yuv444_for_codec = {};
|
||||
|
||||
void
|
||||
reset_display(std::shared_ptr<platf::display_t> &disp, const platf::mem_type_e &type, const std::string &display_name, const config_t &config) {
|
||||
@@ -1396,6 +1447,11 @@ namespace video {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (config.chromaSamplingType == 1 && !video_format[encoder_t::YUV444]) {
|
||||
BOOST_LOG(error) << video_format.name << ": YUV 4:4:4 not supported"sv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto codec = avcodec_find_encoder_by_name(video_format.name.c_str());
|
||||
if (!codec) {
|
||||
BOOST_LOG(error) << "Couldn't open ["sv << video_format.name << ']';
|
||||
@@ -1404,7 +1460,11 @@ namespace video {
|
||||
}
|
||||
|
||||
auto colorspace = encode_device->colorspace;
|
||||
auto sw_fmt = (colorspace.bit_depth == 10) ? platform_formats->avcodec_pix_fmt_10bit : platform_formats->avcodec_pix_fmt_8bit;
|
||||
auto sw_fmt = (colorspace.bit_depth == 8 && config.chromaSamplingType == 0) ? platform_formats->avcodec_pix_fmt_8bit :
|
||||
(colorspace.bit_depth == 8 && config.chromaSamplingType == 1) ? platform_formats->avcodec_pix_fmt_yuv444_8bit :
|
||||
(colorspace.bit_depth == 10 && config.chromaSamplingType == 0) ? platform_formats->avcodec_pix_fmt_10bit :
|
||||
(colorspace.bit_depth == 10 && config.chromaSamplingType == 1) ? platform_formats->avcodec_pix_fmt_yuv444_10bit :
|
||||
AV_PIX_FMT_NONE;
|
||||
|
||||
// Allow up to 1 retry to apply the set of fallback options.
|
||||
//
|
||||
@@ -1421,16 +1481,25 @@ namespace video {
|
||||
|
||||
switch (config.videoFormat) {
|
||||
case 0:
|
||||
ctx->profile = FF_PROFILE_H264_HIGH;
|
||||
// 10-bit h264 encoding is not supported by our streaming protocol
|
||||
assert(!config.dynamicRange);
|
||||
ctx->profile = (config.chromaSamplingType == 1) ? FF_PROFILE_H264_HIGH_444_PREDICTIVE : FF_PROFILE_H264_HIGH;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ctx->profile = config.dynamicRange ? FF_PROFILE_HEVC_MAIN_10 : FF_PROFILE_HEVC_MAIN;
|
||||
if (config.chromaSamplingType == 1) {
|
||||
// HEVC uses the same RExt profile for both 8 and 10 bit YUV 4:4:4 encoding
|
||||
ctx->profile = FF_PROFILE_HEVC_REXT;
|
||||
}
|
||||
else {
|
||||
ctx->profile = config.dynamicRange ? FF_PROFILE_HEVC_MAIN_10 : FF_PROFILE_HEVC_MAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// AV1 supports both 8 and 10 bit encoding with the same Main profile
|
||||
ctx->profile = FF_PROFILE_AV1_MAIN;
|
||||
// but YUV 4:4:4 sampling requires High profile
|
||||
ctx->profile = (config.chromaSamplingType == 1) ? FF_PROFILE_AV1_HIGH : FF_PROFILE_AV1_MAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1561,6 +1630,11 @@ namespace video {
|
||||
for (auto &option : (config.dynamicRange ? video_format.hdr_options : video_format.sdr_options)) {
|
||||
handle_option(option);
|
||||
}
|
||||
if (config.chromaSamplingType == 1) {
|
||||
for (auto &option : (config.dynamicRange ? video_format.hdr444_options : video_format.sdr444_options)) {
|
||||
handle_option(option);
|
||||
}
|
||||
}
|
||||
if (retries > 0) {
|
||||
for (auto &option : video_format.fallback_options) {
|
||||
handle_option(option);
|
||||
@@ -1856,7 +1930,24 @@ namespace video {
|
||||
std::unique_ptr<platf::encode_device_t> result;
|
||||
|
||||
auto colorspace = colorspace_from_client_config(config, disp.is_hdr());
|
||||
auto pix_fmt = (colorspace.bit_depth == 10) ? encoder.platform_formats->pix_fmt_10bit : encoder.platform_formats->pix_fmt_8bit;
|
||||
|
||||
platf::pix_fmt_e pix_fmt;
|
||||
if (config.chromaSamplingType == 1) {
|
||||
// YUV 4:4:4
|
||||
if (!(encoder.flags & YUV444_SUPPORT)) {
|
||||
// Encoder can't support YUV 4:4:4 regardless of hardware capabilities
|
||||
return {};
|
||||
}
|
||||
pix_fmt = (colorspace.bit_depth == 10) ?
|
||||
encoder.platform_formats->pix_fmt_yuv444_10bit :
|
||||
encoder.platform_formats->pix_fmt_yuv444_8bit;
|
||||
}
|
||||
else {
|
||||
// YUV 4:2:0
|
||||
pix_fmt = (colorspace.bit_depth == 10) ?
|
||||
encoder.platform_formats->pix_fmt_10bit :
|
||||
encoder.platform_formats->pix_fmt_8bit;
|
||||
}
|
||||
|
||||
{
|
||||
auto encoder_name = config.videoFormat == 0 ? encoder.h264.name :
|
||||
@@ -2300,8 +2391,8 @@ namespace video {
|
||||
encoder.av1.capabilities.set();
|
||||
|
||||
// First, test encoder viability
|
||||
config_t config_max_ref_frames { 1920, 1080, 60, 1000, 1, 1, 1, 0, 0 };
|
||||
config_t config_autoselect { 1920, 1080, 60, 1000, 1, 0, 1, 0, 0 };
|
||||
config_t config_max_ref_frames { 1920, 1080, 60, 1000, 1, 1, 1, 0, 0, 0 };
|
||||
config_t config_autoselect { 1920, 1080, 60, 1000, 1, 0, 1, 0, 0, 0 };
|
||||
|
||||
// If the encoder isn't supported at all (not even H.264), bail early
|
||||
reset_display(disp, encoder.platform_formats->dev_type, config::video.output_name, config_autoselect);
|
||||
@@ -2420,35 +2511,49 @@ namespace video {
|
||||
encoder.av1.capabilities.reset();
|
||||
}
|
||||
|
||||
std::vector<std::pair<encoder_t::flag_e, config_t>> configs {
|
||||
{ encoder_t::DYNAMIC_RANGE, { 1920, 1080, 60, 1000, 1, 0, 3, 1, 1 } },
|
||||
};
|
||||
// Test HDR and YUV444 support
|
||||
{
|
||||
// H.264 is special because encoders may support YUV 4:4:4 without supporting 10-bit color depth
|
||||
if (encoder.flags & YUV444_SUPPORT) {
|
||||
config_t config_h264_yuv444 { 1920, 1080, 60, 1000, 1, 0, 1, 0, 0, 1 };
|
||||
encoder.h264[encoder_t::YUV444] = validate_config(disp, encoder, config_h264_yuv444);
|
||||
}
|
||||
else {
|
||||
encoder.h264[encoder_t::YUV444] = false;
|
||||
}
|
||||
|
||||
for (auto &[flag, config] : configs) {
|
||||
auto h264 = config;
|
||||
auto hevc = config;
|
||||
auto av1 = config;
|
||||
|
||||
h264.videoFormat = 0;
|
||||
hevc.videoFormat = 1;
|
||||
av1.videoFormat = 2;
|
||||
const config_t generic_hdr_config = { 1920, 1080, 60, 1000, 1, 0, 3, 1, 1, 0 };
|
||||
|
||||
// Reset the display since we're switching from SDR to HDR
|
||||
reset_display(disp, encoder.platform_formats->dev_type, config::video.output_name, config);
|
||||
reset_display(disp, encoder.platform_formats->dev_type, config::video.output_name, generic_hdr_config);
|
||||
if (!disp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto test_hdr_and_yuv444 = [&](auto &flag_map, auto video_format) {
|
||||
auto config = generic_hdr_config;
|
||||
config.videoFormat = video_format;
|
||||
|
||||
if (!flag_map[encoder_t::PASSED]) return;
|
||||
|
||||
// Test 4:4:4 HDR first. If 4:4:4 is supported, 4:2:0 should also be supported.
|
||||
config.chromaSamplingType = 1;
|
||||
if ((encoder.flags & YUV444_SUPPORT) && validate_config(disp, encoder, config) >= 0) {
|
||||
flag_map[encoder_t::DYNAMIC_RANGE] = true;
|
||||
flag_map[encoder_t::YUV444] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Test 4:2:0 HDR
|
||||
config.chromaSamplingType = 0;
|
||||
flag_map[encoder_t::DYNAMIC_RANGE] = validate_config(disp, encoder, config) >= 0;
|
||||
};
|
||||
|
||||
// HDR is not supported with H.264. Don't bother even trying it.
|
||||
encoder.h264[flag] = flag != encoder_t::DYNAMIC_RANGE && validate_config(disp, encoder, h264) >= 0;
|
||||
encoder.h264[encoder_t::DYNAMIC_RANGE] = false;
|
||||
|
||||
if (encoder.hevc[encoder_t::PASSED]) {
|
||||
encoder.hevc[flag] = validate_config(disp, encoder, hevc) >= 0;
|
||||
}
|
||||
|
||||
if (encoder.av1[encoder_t::PASSED]) {
|
||||
encoder.av1[flag] = validate_config(disp, encoder, av1) >= 0;
|
||||
}
|
||||
test_hdr_and_yuv444(encoder.hevc, 1);
|
||||
test_hdr_and_yuv444(encoder.av1, 2);
|
||||
}
|
||||
|
||||
encoder.h264[encoder_t::VUI_PARAMETERS] = encoder.h264[encoder_t::VUI_PARAMETERS] && !config::sunshine.flags[config::flag::FORCE_VIDEO_HEADER_REPLACE];
|
||||
@@ -2605,6 +2710,12 @@ namespace video {
|
||||
auto &encoder = *chosen_encoder;
|
||||
|
||||
last_encoder_probe_supported_ref_frames_invalidation = (encoder.flags & REF_FRAMES_INVALIDATION);
|
||||
last_encoder_probe_supported_yuv444_for_codec[0] = encoder.h264[encoder_t::PASSED] &&
|
||||
encoder.h264[encoder_t::YUV444];
|
||||
last_encoder_probe_supported_yuv444_for_codec[1] = encoder.hevc[encoder_t::PASSED] &&
|
||||
encoder.hevc[encoder_t::YUV444];
|
||||
last_encoder_probe_supported_yuv444_for_codec[2] = encoder.av1[encoder_t::PASSED] &&
|
||||
encoder.av1[encoder_t::YUV444];
|
||||
|
||||
BOOST_LOG(debug) << "------ h264 ------"sv;
|
||||
for (int x = 0; x < encoder_t::MAX_FLAGS; ++x) {
|
||||
@@ -2793,6 +2904,10 @@ namespace video {
|
||||
platf::pix_fmt_e
|
||||
map_pix_fmt(AVPixelFormat fmt) {
|
||||
switch (fmt) {
|
||||
case AV_PIX_FMT_VUYX:
|
||||
return platf::pix_fmt_e::ayuv;
|
||||
case AV_PIX_FMT_XV30:
|
||||
return platf::pix_fmt_e::y410;
|
||||
case AV_PIX_FMT_YUV420P10:
|
||||
return platf::pix_fmt_e::yuv420p10;
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
|
||||
Reference in New Issue
Block a user