obs-ffmpeg: New default AMD encoding settings

This commit is contained in:
Huts, Roman 2024-03-06 14:56:11 -05:00 committed by Roman Huts
parent fb4d65875e
commit 0f18d3914d

View file

@ -1160,16 +1160,38 @@ static void check_texture_encode_capability(obs_encoder_t *encoder,
#include "texture-amf-opts.hpp"
static void amf_defaults(obs_data_t *settings)
static void amf_avc_defaults(obs_data_t *settings)
{
// These are initial recommended settings that may be lowered later
// once we know more info such as the resolution and frame rate.
obs_data_set_default_string(settings, "rate_control", "CBR");
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "rate_control", "CBR");
obs_data_set_default_string(settings, "preset", "quality");
obs_data_set_default_string(settings, "profile", "high");
obs_data_set_default_int(settings, "bf", 3);
}
static void amf_hevc_defaults(obs_data_t *settings)
{
// These are initial recommended settings that may be lowered later
// once we know more info such as the resolution and frame rate.
obs_data_set_default_string(settings, "rate_control", "VBR");
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "preset", "quality");
}
static void amf_av1_defaults(obs_data_t *settings)
{
// These are initial recommended settings that may be lowered later
// once we know more info such as the resolution and frame rate.
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "rate_control", "VBR");
obs_data_set_default_string(settings, "preset", "highQuality");
}
static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
obs_data_t *settings)
{
@ -1229,7 +1251,7 @@ static obs_properties_t *amf_properties_internal(amf_codec_type codec)
add_preset("speed");
#undef add_preset
if (amf_codec_type::AVC == codec || amf_codec_type::AV1 == codec) {
if (amf_codec_type::AVC == codec) {
p = obs_properties_add_list(props, "profile",
obs_module_text("Profile"),
OBS_COMBO_TYPE_LIST,
@ -1339,8 +1361,19 @@ static void amf_avc_update_data(amf_base *enc, int rc, int64_t bitrate,
set_avc_property(enc, PEAK_BITRATE, bitrate);
set_avc_property(enc, VBV_BUFFER_SIZE, bitrate);
if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) {
if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR ||
rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR) {
set_avc_property(enc, FILLER_DATA_ENABLE, true);
} else if (
rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR ||
rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) {
set_avc_property(enc, PEAK_BITRATE, bitrate * 1.5);
set_avc_property(enc, VBV_BUFFER_SIZE, bitrate * 1.5);
} else if (rc ==
AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR) {
int64_t framerate = enc->fps_num / enc->fps_den;
set_avc_property(enc, VBV_BUFFER_SIZE,
(bitrate / framerate) * 1.1);
}
} else {
set_avc_property(enc, QP_I, qp);
@ -1384,10 +1417,50 @@ try {
return false;
}
static inline void check_recommended_avc_defaults(amf_base *enc,
obs_data_t *settings)
{
int64_t framerate = enc->fps_num / enc->fps_den;
if ((enc->cx * enc->cy > 1920 * 1088) || (framerate > 60)) {
// Recommended base defaults
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "rate_control", "CBR");
obs_data_set_default_string(settings, "preset", "quality");
obs_data_set_default_string(settings, "profile", "high");
obs_data_set_default_int(settings, "bf", 0);
info("Original default settings were lowered according to resolution"
" and framerate.");
} else {
// Recommended high perceptual quality defaults
// that are supported up to 1080p60fps
set_avc_property(enc, PRE_ANALYSIS_ENABLE, true);
set_avc_property(enc, ADAPTIVE_MINIGOP, true);
set_amf_property(enc, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 20);
set_amf_property(enc, AMF_PA_TAQ_MODE, AMF_PA_TAQ_MODE_2);
set_amf_property(enc, AMF_PA_ENGINE_TYPE, AMF_MEMORY_OPENCL);
info("High perceptual quality defaults:\n"
"\tEnablePreAnalysis: %s\n"
"\tAdaptiveMiniGOP: %s\n"
"\tPALookAheadBufferDepth: %d\n"
"\tPATemporalAQMode: %d\n"
"\tPAEngineType: %s\n",
"true", "true", 20, AMF_PA_TAQ_MODE_2, "OpenCL");
}
}
static bool amf_avc_init(void *data, obs_data_t *settings)
{
amf_base *enc = (amf_base *)data;
// We originally set the recommended defaults for high perceptual quality in
// the UI settings. Once the resolution and framerate are available here
// during init, we check if the defaults need to be lowered to the base
// defaults or the remaining recommended high perceptual quality settings can
// be set.
check_recommended_avc_defaults(enc, settings);
int64_t bitrate = obs_data_get_int(settings, "bitrate");
int64_t qp = obs_data_get_int(settings, "cqp");
const char *preset = obs_data_get_string(settings, "preset");
@ -1417,12 +1490,13 @@ static bool amf_avc_init(void *data, obs_data_t *settings)
int rc = get_avc_rate_control(rc_str);
set_avc_property(enc, RATE_CONTROL_METHOD, rc);
if (rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP)
if (rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP &&
rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR &&
rc != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR)
set_avc_property(enc, ENABLE_VBAQ, true);
amf_avc_update_data(enc, rc, bitrate * 1000, qp);
set_avc_property(enc, ENFORCE_HRD, true);
set_avc_property(enc, HIGH_MOTION_QUALITY_BOOST_ENABLE, false);
int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
@ -1451,17 +1525,17 @@ static bool amf_avc_init(void *data, obs_data_t *settings)
if (!ffmpeg_opts || !*ffmpeg_opts)
ffmpeg_opts = "(none)";
info("settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\tb-frames: %d\n"
"\twidth: %d\n"
"\theight: %d\n"
"\tparams: %s",
info("Settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\tmax b-frames: %d\n"
"\twidth: %d\n"
"\theight: %d\n"
"\toverriding params: %s",
rc_str, bitrate, qp, gop_size, preset, profile, bf, enc->cx,
enc->cy, ffmpeg_opts);
@ -1614,7 +1688,7 @@ static void register_avc()
amf_encoder_info.destroy = amf_destroy;
amf_encoder_info.update = amf_avc_update;
amf_encoder_info.encode_texture = amf_encode_tex;
amf_encoder_info.get_defaults = amf_defaults;
amf_encoder_info.get_defaults = amf_avc_defaults;
amf_encoder_info.get_properties = amf_avc_properties;
amf_encoder_info.get_extra_data = amf_extra_data;
amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE |
@ -1675,6 +1749,18 @@ static inline int get_hevc_rate_control(const char *rc_str)
return AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR;
}
static inline int get_hevc_profile(obs_data_t *settings)
{
const char *profile = obs_data_get_string(settings, "profile");
if (astrcmpi(profile, "main") == 0)
return AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN;
else if (astrcmpi(profile, "main10") == 0)
return AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10;
return AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN;
}
static void amf_hevc_update_data(amf_base *enc, int rc, int64_t bitrate,
int64_t qp)
{
@ -1684,8 +1770,19 @@ static void amf_hevc_update_data(amf_base *enc, int rc, int64_t bitrate,
set_hevc_property(enc, PEAK_BITRATE, bitrate);
set_hevc_property(enc, VBV_BUFFER_SIZE, bitrate);
if (rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR) {
if (rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR ||
rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR) {
set_hevc_property(enc, FILLER_DATA_ENABLE, true);
} else if (
rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR ||
rc == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) {
set_hevc_property(enc, PEAK_BITRATE, bitrate * 1.5);
set_hevc_property(enc, VBV_BUFFER_SIZE, bitrate * 1.5);
} else if (rc ==
AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR) {
int64_t framerate = enc->fps_num / enc->fps_den;
set_hevc_property(enc, VBV_BUFFER_SIZE,
(bitrate / framerate) * 1.1);
}
} else {
set_hevc_property(enc, QP_I, qp);
@ -1728,10 +1825,46 @@ try {
return false;
}
static inline void check_recommended_hevc_defaults(amf_base *enc,
obs_data_t *settings)
{
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
const int64_t framerate = enc->fps_num / enc->fps_den;
if ((enc->cx * enc->cy > 1920 * 1088) || is10bit || (framerate > 60)) {
// Recommended base defaults
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "preset", "quality");
info("Original default settings were lowered according to resolution"
" and framerate.");
} else {
// Recommended high perceptual quality defaults
// that are supported up to 1080p60fps
set_hevc_property(enc, PRE_ANALYSIS_ENABLE, true);
set_amf_property(enc, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 20);
set_amf_property(enc, AMF_PA_TAQ_MODE, AMF_PA_TAQ_MODE_2);
set_amf_property(enc, AMF_PA_ENGINE_TYPE, AMF_MEMORY_OPENCL);
info("High perceptual quality defaults:\n"
"\tHevcEnablePreAnalysis: %s\n"
"\tPALookAheadBufferDepth: %d\n"
"\tPATemporalAQMode: %d\n"
"\tPAEngineType: %s\n",
"true", 20, AMF_PA_TAQ_MODE_2, "OpenCL");
}
}
static bool amf_hevc_init(void *data, obs_data_t *settings)
{
amf_base *enc = (amf_base *)data;
// We originally set the recommended defaults for high perceptual quality in
// the UI settings. Once the resolution and framerate are available here
// during init, we check if the defaults need to be lowered to the base
// defaults or the remaining recommended high perceptual quality settings can
// be set.
check_recommended_hevc_defaults(enc, settings);
int64_t bitrate = obs_data_get_int(settings, "bitrate");
int64_t qp = obs_data_get_int(settings, "cqp");
const char *preset = obs_data_get_string(settings, "preset");
@ -1740,12 +1873,13 @@ static bool amf_hevc_init(void *data, obs_data_t *settings)
int rc = get_hevc_rate_control(rc_str);
set_hevc_property(enc, RATE_CONTROL_METHOD, rc);
if (rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP)
if (rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP &&
rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR &&
rc != AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR)
set_hevc_property(enc, ENABLE_VBAQ, true);
amf_hevc_update_data(enc, rc, bitrate * 1000, qp);
set_hevc_property(enc, ENFORCE_HRD, true);
set_hevc_property(enc, HIGH_MOTION_QUALITY_BOOST_ENABLE, false);
int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
@ -1768,16 +1902,16 @@ static bool amf_hevc_init(void *data, obs_data_t *settings)
if (!ffmpeg_opts || !*ffmpeg_opts)
ffmpeg_opts = "(none)";
info("settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\twidth: %d\n"
"\theight: %d\n"
"\tparams: %s",
info("Settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\twidth: %d\n"
"\theight: %d\n"
"\toverriding params: %s",
rc_str, bitrate, qp, gop_size, preset, profile, enc->cx, enc->cy,
ffmpeg_opts);
@ -1835,6 +1969,7 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings)
const bool hlg = is_hlg(enc);
const bool is_hdr = pq || hlg;
const char *preset = obs_data_get_string(settings, "preset");
obs_data_set_string(settings, "profile", is10bit ? "main10" : "main");
set_hevc_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy));
set_hevc_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING);
@ -1842,9 +1977,7 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings)
set_hevc_property(enc, COLOR_BIT_DEPTH,
is10bit ? AMF_COLOR_BIT_DEPTH_10
: AMF_COLOR_BIT_DEPTH_8);
set_hevc_property(enc, PROFILE,
is10bit ? AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10
: AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN);
set_hevc_property(enc, PROFILE, get_hevc_profile(settings));
set_hevc_property(enc, LOWLATENCY_MODE, false);
set_hevc_property(enc, OUTPUT_COLOR_PROFILE, enc->amf_color_profile);
set_hevc_property(enc, OUTPUT_TRANSFER_CHARACTERISTIC,
@ -1960,6 +2093,17 @@ try {
return nullptr;
}
/* These are initial recommended settings that may be lowered later
* once we know more info such as the resolution and frame rate.
*/
static void amf_hevc_defaults(obs_data_t *settings)
{
obs_data_set_default_string(settings, "rate_control", "CBR");
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "preset", "quality");
}
static void register_hevc()
{
struct obs_encoder_info amf_encoder_info = {};
@ -1971,7 +2115,7 @@ static void register_hevc()
amf_encoder_info.destroy = amf_destroy;
amf_encoder_info.update = amf_hevc_update;
amf_encoder_info.encode_texture = amf_encode_tex;
amf_encoder_info.get_defaults = amf_defaults;
amf_encoder_info.get_defaults = amf_hevc_defaults;
amf_encoder_info.get_properties = amf_hevc_properties;
amf_encoder_info.get_extra_data = amf_extra_data;
amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE |
@ -2055,12 +2199,19 @@ static void amf_av1_update_data(amf_base *enc, int rc, int64_t bitrate,
set_av1_property(enc, PEAK_BITRATE, bitrate);
set_av1_property(enc, VBV_BUFFER_SIZE, bitrate);
if (rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) {
if (rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR ||
rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_CBR) {
set_av1_property(enc, FILLER_DATA, true);
} else if (
rc == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR ||
rc == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_HIGH_QUALITY_VBR) {
set_av1_property(enc, PEAK_BITRATE, bitrate * 1.5);
set_av1_property(enc, VBV_BUFFER_SIZE, bitrate * 1.5);
} else if (rc ==
AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR) {
int64_t framerate = enc->fps_num / enc->fps_den;
set_av1_property(enc, VBV_BUFFER_SIZE,
(bitrate / framerate) * 1.1);
}
} else {
int64_t qp = cq_value * 4;
@ -2104,10 +2255,47 @@ try {
return false;
}
static inline void check_recommended_av1_defaults(amf_base *enc,
obs_data_t *settings)
{
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
const int64_t framerate = enc->fps_num / enc->fps_den;
if ((enc->cx * enc->cy > 1920 * 1088) || is10bit || (framerate > 60)) {
// Recommended base defaults
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "preset", "balanced");
obs_data_set_default_string(settings, "profile", "main");
info("Original default settings were lowered according to resolution"
" and framerate.");
} else {
// Recommended high perceptual quality defaults
// that are supported up to 1080p60fps
set_av1_property(enc, PRE_ANALYSIS_ENABLE, true);
set_amf_property(enc, AMF_PA_LOOKAHEAD_BUFFER_DEPTH, 20);
set_amf_property(enc, AMF_PA_TAQ_MODE, AMF_PA_TAQ_MODE_2);
set_amf_property(enc, AMF_PA_ENGINE_TYPE, AMF_MEMORY_OPENCL);
info("High perceptual quality defaults:\n"
"\tAv1EnablePreAnalysis: %s\n"
"\tPALookAheadBufferDepth: %d\n"
"\tPATemporalAQMode: %d\n"
"\tPAEngineType: %s\n",
"true", 20, AMF_PA_TAQ_MODE_2, "OpenCL");
}
}
static bool amf_av1_init(void *data, obs_data_t *settings)
{
amf_base *enc = (amf_base *)data;
// We originally set the recommended defaults for high perceptual quality in
// the UI settings. Once the resolution and framerate are available here
// during init, we check if the defaults need to be lowered to the base
// defaults or the remaining recommended high perceptual quality settings can
// be set.
check_recommended_av1_defaults(enc, settings);
int64_t bitrate = obs_data_get_int(settings, "bitrate");
int64_t qp = obs_data_get_int(settings, "cqp");
const char *preset = obs_data_get_string(settings, "preset");
@ -2119,8 +2307,6 @@ static bool amf_av1_init(void *data, obs_data_t *settings)
amf_av1_update_data(enc, rc, bitrate * 1000, qp);
set_av1_property(enc, ENFORCE_HRD, true);
int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
int gop_size = (keyint_sec) ? keyint_sec * enc->fps_num / enc->fps_den
: 250;
@ -2140,18 +2326,20 @@ static bool amf_av1_init(void *data, obs_data_t *settings)
if (!ffmpeg_opts || !*ffmpeg_opts)
ffmpeg_opts = "(none)";
info("settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\twidth: %d\n"
"\theight: %d\n"
"\tparams: %s",
info("Settings:\n"
"\trate_control: %s\n"
"\tbitrate: %d\n"
"\tcqp: %d\n"
"\tkeyint: %d\n"
"\tpreset: %s\n"
"\tprofile: %s\n"
"\twidth: %d\n"
"\theight: %d\n"
"\tscreen content tools: %s\n"
"\tpalette mode: %s\n"
"\toverriding params: %s",
rc_str, bitrate, qp, gop_size, preset, profile, enc->cx, enc->cy,
ffmpeg_opts);
"true", "true", ffmpeg_opts);
return true;
}
@ -2177,6 +2365,7 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings)
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
const char *preset = obs_data_get_string(settings, "preset");
obs_data_set_string(settings, "profile", "main");
set_av1_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy));
set_av1_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING);
@ -2194,7 +2383,8 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings)
set_av1_property(enc, OUTPUT_TRANSFER_CHARACTERISTIC,
enc->amf_characteristic);
set_av1_property(enc, OUTPUT_COLOR_PRIMARIES, enc->amf_primaries);
set_av1_property(enc, FRAMERATE, enc->amf_frame_rate);
set_av1_property(enc, SCREEN_CONTENT_TOOLS, true);
set_av1_property(enc, PALETTE_MODE, true);
amf_av1_init(enc, settings);
@ -2280,13 +2470,15 @@ try {
return nullptr;
}
/* These are initial recommended settings that may be lowered later
* once we know more info such as the resolution and frame rate.
*/
static void amf_av1_defaults(obs_data_t *settings)
{
obs_data_set_default_int(settings, "bitrate", 2500);
obs_data_set_default_int(settings, "cqp", 20);
obs_data_set_default_string(settings, "rate_control", "CBR");
obs_data_set_default_string(settings, "preset", "quality");
obs_data_set_default_string(settings, "profile", "high");
obs_data_set_default_string(settings, "preset", "highQuality");
}
static void register_av1()